"Turn" to solve the single-chip multi-byte serial port receive (serial port multi-byte receive send high-order research)

Source: Internet
Author: User

The single chip microcomputer multi-byte serial port receive (high-order research of serial port multi-byte receive send)

Original address: Http://bbs.ednchina.com/BLOG_ARTICLE_3007162.HTM

Work for more than a year, wrote a lot of single-chip computer serial program. The sense of the serial port multi-byte receive part of the logic relative to the configuration register with the serial port reply, is a bit difficult--register configuration is basically dead, serial port reply multibyte and reply to a byte just a loop.

Serial receiver program is based on serial interrupt, single-chip computer serial port each time receive one byte of data to produce one interrupt, and then read a register to get the serial port to receive data. In practical applications, however, there is basically no single-byte reception. are generally based on a certain serial port communication protocol of multi-byte communication. In 422 or 485 communication, it may also be a host (usually a computer) with multiple slave machines (corresponding board cards with a single chip). This requires our microcontroller to be able to continuously receive the serial data sequence to identify the corresponding card in accordance with their own communication protocol, to control the operation, non-compliance without any action. In a nutshell, a single piece of data finds several bytes of data that conform to a certain pattern.

First of all, how to set the serial port protocol it. This protocol refers not to the protocol at the bottom of the serial port, but to the data frame protocol mentioned earlier. Usually there is a frame head (two or three bytes), the data (length as required), the end bit (1 bits, sometimes designed to check the byte, the simplest check is the sum of all previous data).

For example 0XAA 0x55 + (data part omitted) + checksum (except AA 55 and the sum of data), if a multi-board card, sometimes also to add a board after the frame of the selected byte (equivalent to 3 byte frame header).

The first time I write a serial receiver, the first thing I think of is to define a global variable (in fact, it is best to define a local static variable), the initial value is set to 0, and then each time the interrupt +1, and then added to the length of the serial communication protocol to clear Zero. Then determine the frame header, check. After writing it all I feel wrong, once the data staggered one, the back will never receive the number. Helplessly looked at the predecessors of the Code, and my idea is similar, but that the count value with the received data at the same time to judge, and each interrupt to judge, once the count of the variable is zeroed.

Talk less, directly on a piece of code to let people look at the understanding. (The communication protocol is based on a simple AA 551 byte data One byte checksum, the code is on the basis of 51 microcontroller). Receiving success in the interrupt program to receive the success of the serial port flag position 1.

Here is the global variable definition

1 Char receive[4]={0,0,0,0}; // Receive Cache 2 3 bit uart_flag; // Serial port receiving success sign

Then the serial port interrupts the part

voidSer () interrupt4{

StaticUnsignedCharCount//serial port receive count variableRi=0;//manually clear a register, everyone knows.receive[count]=Sbuf; if(count==0&&receive[count]==0xaa)//at the same time, count and the data received{Count=1; } Else if(count==1&&receive[count]==0x55) {Count=2; } Else if(count==2) {Count++; } Else if(count==3&&receive[count]== Receive [2])//Judging the checksum, the number of data is to ask//and, or other methods of calibration, may also be fixed frame endings{Count=0; Uart_flag=1;//The serial port receives the success flag, replies to 1 o'clock in the main program, then clear 0es=0;//shut down, reply finished again Es=1; } Else{Count=0;//The count value is cleared 0 if the condition is not met }}

The first time to do the serial port probably in accordance with this method is finished (I later read the other code, some people write with a switch statement, logic is similar to this, but I still feel that if else to write clearly),

However, when the test found a bug, if the data frame sent half, then suddenly stop, and then re-send, will lose a frame of data. For example, first accept AA 55, then break, and then come in AA 55 01 01, it is not controlled. Later I also think of a bug, if in the multi-device communication, the last one of the frame data belonging to other devices is AA (or the last two bits are AA 55, or the last 3 bits are AA 55 board selected), the next communication data will not be received.

At that time the data suddenly interrupted the bug, did not think of a good solution, but this situation is very small, so always use this method to write no problem. Multi-device communication The last one that happens to be AA is also very small, and the problem may be small. At that time the control data inside the project and the check was not possible AA, so I changed if (COUNT==0&&RECEIVE[COUNT]==0XAA) to the IF (RECEIVE[COUNT]==0XAA) other has not changed, resolved, There's no bug.

Then I wrote a few times single-chip computer program, only to think of some solutions to the problem-but another day to write it, too tired, and tomorrow to work.

In later projects, it is true that the data bits and the check digit may appear aa. I consider that every time the data is sent continuously (at least we use labwindows do the host computer program is such), successfully received a frame of data is to have a certain time to reply, that is, if received half, but a long time did not receive the data, Count value count clear 0 OK. Time-related issues naturally need to be implemented with timers.

This communication protocol, such as the serial port baud rate 19200, 2 frame head AA 55, a board selection, 6 bytes of data, a check byte (except the frame header and other data).

global variable definition

Char boardaddr; // Board Select Address, through the detection of several IO pins, specifically how to get not written, very simple  Char g_datrev []={0}; // Receive Cache bit Retflag=0;// 1 for the serial port received a frame of data

Serial port initialization function, crystal oscillator 22.1184

voidInit_uart () {SCON=0x50;//serial Port Mode 1 allows receivingTmod =0x21;//Timer 1, Mode 2, 8-bit auto reload, simultaneously configure timer 0, working mode 1PCON =0x80;//double the baud rateTH1 =0XFA; TL1=0XFA;//Write serial timer initial valueTh0= (65536- -)/ the;//Write timer 0 initial value, serial port transmission One byte time is (1/19200) *10, calculate 0.52msTl0= (65536- -)% the;//Timer 0 Timing about 1ms moreEa=1; ET0=1;//baud rate: 19200 22.1184M initial value: (0XFA)IE |=0x90; TR1=1; }

Serial Interrupt function

voidUart_int (void) Interrupt4{        StaticUnsignedCharCount//serial port receive count variableRI =0; G_datrev[count]=Sbuf; if(g_datrev[count]==0xaa&&count==0)//Frame Header{Count=1; }               Else if(count==1&&g_datrev[count]==0x55) {Count=2; }                Else if(count==2&&g_datrev[2] ==boardaddr) {CK=G_datrev[count]; Count=3; }               Else if(count>=3&&count<9) {CK+=G_datrev[count]; Count++; }           Else if(Count = =9&&ck==g_datrev[9]) {ES=0; Retflag=1; Count=0; }                          Else{Count=0; } resettimer ();}

//Start the Timer if count is not 0voidResettimer () {TR0=0; TH0=(65536- -)/ the; TL0=(65536- -)% the; if(count!=0) {TR0=1; }} Timer Interrupt functionvoidT0_time () Interrupt1{TR0=0; TH0=(65536- -)/ the; TL0=(65536- -)% the; Count=0;}

This method is really my own thought out, others may have done so, but I definitely do not copy or imitate. This is true to avoid the aforementioned bug, but at the cost of more than one timer resource, and the interrupt function is more content, taking up more time.

If we can improve the first method, it is mainly that the check can not be AA of the bug, because after all, the transmission to half a sudden break of the possibility is very small. Then I think the first to judge if (COUNT==0&&RECEIVE[COUNT]==0XAA) seems to be a bit too strict, considering the second byte of the frame head, with the board to select the address can not be AA, so rewrite this as if (count>=0& &count<=2&& Receive[count]==0xaa), so that the probability of the occurrence of the bug dropped to very small, but only at the end of the previous frame of the data is a AA 55 board election only to appear, the odds are how many of us to calculate it, hehe. In this way, I think, yesterday wrote the kind of method to improve to this extent, it should be OK, anyway, I am very satisfied.

In fact, I have thought of other methods, such as cached arrays with shift hosting. Take the previous 4-byte protocol as an example.

void Ser () Interrupt 4

{

unsigned char i;

ri=0;

for (i=0;i<3;i++)

{

RECEIVE[I]=RECEIVE[I+1];

}

Receive[3]=sbuf;

if (Reveive[0]==0xaa&&receive[1]==0x55&&receive[2]==receive[3])

{

ret_flag=1;

ES = 0;

}

}

This code looks simple and straightforward, so the judgment is good, and judging the frame header and checksum does not produce the aforementioned bug. To tell you the truth, when I first came up with this method and wrote it, I was given the right. The For loop really takes up a lot of time, ah, the delay function is written in this way. Each time the cycle, the delay is too long, the communication speed is too fast, you can not receive the next byte of data. The most fatal thing is that the length of this time is increased with the number of bytes in the communication protocol frame, and if you want to receive dozens of bytes at a moment, you must be finished. I didn't use this method once.

But I thought I'd come out again. This method of improvement measures, the first two days just came out of, hehe, haven't practiced yet.

The protocol for the following code is the second program (the protocol that the timer zeroed out, altogether 10 bytes)

Global variables

Bit ret_flag;

unsigned char receive[256]={0};

unsigned char boardaddress;

Interrupt function

void Ser () Interrupt 4

{

static unsigned char i=0;

static unsigned char total=0;

ri=0;

Receive[i]=sbuf;

TOTAL=TOTAL-RECEIVE[I-7]+RECEIVE[I-1];

if (receive[i-9]==0xaa&&receive[i-8]==0x55 && receive[i-7]==boardaddress&&receive[i]== Total

{

ret_flag=1;

ES = 0;

}

i++;

}

A 256-length array is defined to allow the array to "end to end". Because 0-1 = 255, 255+1 = 0. And I also improved the algorithm when calculating the checksum, and did not increase the time to calculate the checksum because of the increase in the length of the data. This method is also not a long ago I thought out, so has not been verified by the actual. The above code may have a logical error, if there is a mistake, a netizen to see, please leave a message below to tell me. This method is also my original Oh, others will be able to think of, but I this is definitely not copied others.

The biggest drawback of the above code is that the variable definition is too much, the amount of RAM resources, compile the time may be wrong, after all, 51 MCU only 128 bytes of RAM (some resources are also very rich, such as the c8051 series), this is a 256-byte variable. But for the more resources of the microcontroller, so write is still possible. If can have 4bit together of data type is good, hehe, Verilog code inside is can, C language seemingly not AH.

To be able to run on such as 51 single-chip microcomputer, only according to the following compromise, that is, I related to the amount of a 0x0f

Global variables

Bit ret_flag;

unsigned char receive[16]={0};//may consider adding idata to the definition, after all, it could be 32.

or an array of 64 lengths unsigned char idata receive[16]={0};

unsigned char boardaddress;

Interrupt function

void Ser () Interrupt 4

{

static unsigned char i=0;

static unsigned char total=0;

ri=0;

receive[i&0x0f]=sbuf;

total=total-receive[(i-7) &0x0f]+receive[(i-1) &0x0f];

if (receive[(i-9) &0x0f]==0xaa&&receive[(i-8) &0x0f]==0x55

&&receive[(i-7) &0x0f]==boardaddress&&receive[i&0x0f]==total

)

{

ret_flag=1;

ES = 0;

}

i++;

}

That's all you can do. When I have a chance to try it, hehe. I wrote so many, presumably everyone can handle the serial port to receive it.

PS: The font is a little small, we make a look, edit the font of the words to show the word super, really not I made lazy oh.

"Turn" to solve the single-chip multi-byte serial port receive (serial port multi-byte receive send high-order research)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.