串口的收发可以用查询和中断两个办法来实现。
1、查询方法更适合于半双工机制,编写的思路简单,程序结构简单,在全双工通信中易出问题。
2、中断方法则更高效。你的程序把两种方法混搭使用,容易出错。
以你的程序为例,一旦收到首个23H字符,就停止在中断服务中for循环里面等待5个剩余字符。假设传感器只发了3个字符,你的程序就停止在for循环里面。
以你的程序为例改进,在中断服务接收中,每次接收中断只收1个字符,完成后退出。
void uart_interrupt(void) interrupt 4 using 0
{
static unsigned char i=0;
unsigned char buf;
if(RI==1)
{
buf=SBUF;
switch(i)
{
case 0:
if(buf==0x23)i=1;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
buffer[i-1]=buf;
i++;
if(buf==0x23)
i=1;
if(i==5)
{
do_something_here(buffer);
i=0;
}
break;
default: i=0;break;
}
RI = 0; //RI清零
}
if(TI==1) TI=0; //TI清零
}
这样改符合你的思维习惯吗?实际串口协议解析与协议密切相关,用状态机做比较好。程序中i把它变成状态机的状态,思考一下,改改程序更佳。
ORG 0000H
SJMP 0050H
ORG 0023H
LJMP S_INT
TAB:DB 20H,49H,20H,47H,45H,54H,20H,'NULL'
ORG 0050H
MOV TMOD,#20H
MOV TH1,#0FDH
MOV TL1,#0FDH
SETB TR1
SETB SM1
CLR SM0
SETB EA
SETB ES
MOV R0,#30H
MOV A,#1H
MAIN:SETB REN
ACALL DELAY
JNZ MAIN
MOV R2,#0
MOV DPTR,#TAB
MOV R7,#7
SEND:MOV A,R2
MOVC A,@A+DPTR
CLR ES
MOV SBUF,A
JNB TI,$
CLR TI
INC R2
DJNZ R7,SEND
MOV R0,#30H
SHOW:MOV A,@R0
MOV SBUF,A
JNB TI,$
CLR TI
INC R0
CJNE A,#40H,SHOW
SETB ES
MOV A,#1
MOV R0,#30H
SJMP MAIN
S_INT:CLR RI
MOV A,SBUF
MOV @R0,A
CJNE A,#40H,NEXT
MOV A,#0
NEXT:INC R0
RETI
DELAY:MOV 7DH,#200
LOOP1:MOV 7EH,#40
DJNZ 7EH,$
DJNZ 7DH,LOOP1
RET
END
这个是方式一的
串行发送程序 Txasm :
PCON, #00H ;; 波特率不倍增
SETB TR1 ;; 启动定时器T1
MOV IE, #0 ;; 禁止任何中断
CALL DLY125 ;; 延时125ms
;;--------------------------------------------
T_X: ;; 透传发送字串
ACALL DSPLED ;; P20控制LED闪亮
MOV R3, #4 ;; 待发送字符个数
MOV DPTR, #TAB_TX ;; 数据表首址
TX_LP1: CLR A
MOVC A, @A+DPTR ;; A←数据表的1个字符
CLR TI ;; TI清零,允许发送
MOV SBUF,A ;; 发送1个字符
JNB TI, $ ;; 等待1个字符帧发送结束
DJNZ R3, TX_next
CALL DLY500 ;; 延时500ms
SJMP T_X ;; 重复发送
TX_next: ;; 发送另一字符
INC DPTR ;; 数据表指针移动
SJMP TX_LP1
;;--------------------------------------------
DSPLED: ;;开机或复位,P20控制LED闪亮6遍
MOV R2, #6 ;; 循环次数
LEDLP1: CLR P20 ;; LED亮
CALL DLY125 ;; 延时125ms
SETB P20 ;; LED灭
CALL DLY125
DJNZ R2,LEDLP1 ;; 循环
RET
;;----------------------------------------------
DLY125: ;; 延时125ms
DLY125A: MOV R5,#250
DLY125B: MOV R6,#250
DJNZ R6,$
DJNZ R5,DLY125B
RET
;; 2502502μs=125 000μs =125ms
;;----------------------------------------------
DLY500: ;; 延时500ms
MOV R7,#4
DLY500A: MOV R6,#250
DLY500B: MOV R5,#250
DJNZ R5,$
DJNZ R6,DLY500B
DJNZ R7,DLY500A
RET
;; 42502502μs=500 000μs =500ms
;;-------------------------------------------------
TAB_TX: DB 38H,30H,35H,31H,
;; 8 0 5 1
;;----------------------------------------------
END
#include <REG52H>
#define uchar unsigned char
#define uint unsigned int
sbit ring=P3^7;
sbit CASE1=P2^0;
sbit CASE2=P2^1;
sbit CASE3=P2^2;
sbit CASE4=P2^3;
uchar se=0,re=0;
uchar temp=0;
void wait(uint cnt)
{
while(--cnt);
}
//串口发送程序
void send(uchar se)
{
SBUF=se; //发送数据
while(TI == 0);
TI = 0;
}
//串口接收程序
uchar receive(void)
{
re=SBUF; //接收数据
while(RI==0);
RI=0;
return re;
}
//串口初始化
void sinti(void)
{
SCON = 0x50;
TMOD |= 0x20;
TH1 = 0xFD;
TR1 = 1;
EA = 1;
ES = 1;
}
void delay(int cnt)
{
while(--cnt);
}
//主程序
int main (void)
{
int i;
sinti(); //串口初始化程序
ring=1;
while(1)
{
while (1)
{
if(CASE1==0)
{
send('a');
ring=0;
break;
}
if(CASE2==0)
{
send('b');
ring=0;
break;
}
if(CASE3==0)
{
send('c');
ring=0;
break;
}
if(CASE4==0)
{
send('d');
ring=0;
break;
}
}
if(ring==0)
{
wait(60000);
ring=1;
}
for(i=0;i<10000;i++);
}
}
//串口中断程序
void UART_SER (void) interrupt 4 //串行中断服务程序
{
if(RI) //判断是接收中断产生
{
RI=0; //标志位清零
temp=SBUF;
}
if(TI) //如果是发送标志位,清零
TI=0;
}
while(RI); //接收数据,若字符未接受完,一直等待
{
RI=0;
temp[num]=SBUF;
num++;
endmark=1;
/
假如你波特率为9600,那么接收一个位时间大概为100us,假如你的单片机执行一条语句1us,
那么你用查询的方式有可能会是你只接收到第一个字节后,就会推出这个while循环
/
}
建议你用串口中断的方式来接收多个字节的数据,下面是我之前写过的程序
/
串口中断函数
ReData[]: 里是一个字节类型的数组,这里一次只接收4个字节数据
/
void Usart_isr() interrupt 4 using 2
{
if(RI)
{
ReData[ReceiveCount++] = SBUF;
if(ReceiveCount > 3)
{
ReceiveCount = 0;
}
RI = 0;
}
}
#include <AT89X51H>//单片机51头文件,存放着单片机的寄存器
unsigned char dat; //用于存储单片机接收发送缓冲寄存器SBUF里面的内容
sbit gewei=P2^2; //个位选通定义
sbit shiwei=P2^3; //十位选通定义
unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x77,0x7c,0x39,0x5e,0x79,0x71};
//{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,};// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
void Delay(unsigned int tc) //延时程序
{
while( tc != 0 )
{unsigned int i;
for(i=0; i<100; i++);
tc--;}
}
void LED() //LED显示接收到的数据
{
shiwei=0;
P0=~table[dat/16];
Delay(8);
shiwei=1;
gewei=0;
P0=~table[dat%16];
Delay(5);
gewei=1;
}
void Init_Com(void)//功能:串口初始化,波特率9600,方式1
{
TMOD = 0x20;
PCON = 0x00;
SCON = 0x50;
TH1 = 0xFd;
TL1 = 0xFd;
TR1 = 1;
}
void main()//主程序功能:实现接收数据并把接收到的数据原样发送回去///////
{
Init_Com();//串口初始化
// P1=0xf0;
while(1)
{
if ( RI ) //扫描判断是否接收到数据,
{
dat = SBUF; //接收数据SBUF赋与dat
RI=0; //RI清零。
SBUF = dat; //在原样把数据发送回去
}
LED(); //显示接收到的数据
}
}
以上就是关于51单片机如何进行多字节串口接收!!!全部的内容,包括:51单片机如何进行多字节串口接收!!!、51单片机汇编语言写串口程序、两个51单片机串口通信程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)