设为首页
收藏本站
PLC技术网
开启辅助访问
切换到宽版
登录
注册哦
只需一步,快速开始
微信扫码登录
门户
Portal
论坛
BBS
导读
排行榜
积分充值
帖子
搜索
本版
文章
帖子
用户
PLC论坛-全力打造可编程控制器专业技术论坛
»
论坛
›
工控技术交流区
›
『国外:三菱/西门子/欧姆龙/松下』
›
单片机串口接收未知长度的字节数据程序实例 ...
返回列表
发新帖
[西门子]
单片机串口接收未知长度的字节数据程序实例
[复制链接]
108
|
0
|
2025-4-13 20:38:07
|
显示全部楼层
|
阅读模式
单片机串口通过接收中断来判断接收数据,通常我们接收数据长度是确定的数,可以通过建立数组,将接收的数据不断放入数组中,当达到所要接收的长度,做判断,表示接收完成,再进行下一步的程序。但如果接收的数据并不知道其长度,那怎么判断是否接收完毕呢。
通常我们可以做一个空闲等待,即在一定时间内没有接收到数据,我们就可以认为他不在发送。
通常空闲等待时间
5ms,当然可以更长,传输的数据也更稳定。
我以等待5ms没有发过来数据来认定不在发送。
在串口中断函数里面,每接收到一个字节,就会把接收到的字节保存到Rx_R[]数组中,Rx_R[]可以事先定义一个较大的数组,足可以放下所要接收的字符串。但如果太大,会报错:segment too large。所以如果定义较大的数组,如Rx_R[255],需要加入code区才可以。在文中,我定义了Rx_R[30],因为所接收的字符串小于30。
unsigned char flag_R=0; //接收标志位
unsigned char flag_T=0; //发送标志位
unsigned char flag_Time=0; //时间计时
unsigned char Tx_R='R'; //发送字符为R
unsigned char Rx_R[30];//接收数组,定义要大于接收数
unsigned char Res_Count; //默认是0
在串口中断函数里面,每接收到一个字节,
变量
Res_Count
作为
字节计数器
+1。每当flag_R
置
1,
flag_Time置0,
表示接收完毕。
// 串口1 中断服务程序
void UART1(void) interrupt 4
{
if(TI)
// 发送完成中断
{
TI=0;
flag_T=1; //接收完毕标志,接收一个'R
'
}
if(RI)
// 接收完成中断 RI==1,接收完成一个字节
{
RI=0;
Rx_R[Res_Count] = SBUF;
Res_Count++;
flag_R=1; //接收完成标志位置1
flag_Time=0; //延时计数清零
}
}
在主函数当中,发现变量
flag_Time
等于
1了,就开始启动延时计数让这个变量
每
1ms加1
。
每当接收到数据后
flag_Time又为0,
只要
一直接收,
flag_Time就一直为0。
如果串口不停的收数据,永不停顿,那
Res_Times
永
远
也到不了5。
直到停顿
5ms了未收到数据,认为不在发送,看做一个完整字节串结束。当不在接收后,flag_Time经过5ms,此时
flag_Time
已经加到5,退出do循环,此时认为接收完毕,执行
Res_Count
为
0,准备下一次的接收或下面的程序运行。同时给数组加\0,表示此字节串到此为止。
main()
{
UART1_init();
while(1)
{
unsigned int j=0;
unsigned int k=0;
SendDataByUart1('R');
for(j=0;j<1000;j++)//发完后延迟等待1s,同时等待接收
{
Delay1000us();
}
do{
flag_Time++; // 延时计数器+1
Delay1000us(); //延迟1ms
}while(flag_Time<5);
// 5ms时间到,flag_Time仍未置0,表示5ms没有收到数据。
//相当于空闲等待5ms。
//下面写所要进行的程序
flag_R=0;
// 接收标志清0
Rx_R[Res_Count] ='\0';
//空闲5ms未收到后,表示结束,加结束符。
Res_Count=0; // 接收数据字节计数器清0
sendcombytes(Rx_R);
//向1口发送
for(j=0;j<500;j++)//发完后延迟等待0.5s,同时等待接收
{
Delay1000us();
}
}
}
以
STC15W为案例
每秒向串口助手发送
R,向单片机回复字符串,单片机将回复的字符串打印在串口助手上。
#define
MAIN_Fosc
11059200L
//定义主时钟,注意和下载频率选择一致
#define
uint16 unsigned int
#define
uint8 unsigned char
#include
#include
"STC15.H"
#include
#define
T_MS 5 //定时时间常量,单位ms
#define
T1TMS (T_MS*MAIN_Fosc/1000) //1T模式下
#define
T12TMS (T_MS*MAIN_Fosc/1000/12) //12T模式下
unsigned char
flag_R=0; //接收标志位
unsigned char
flag_T=0; //发送标志位
unsigned char
flag_Time=0;//时间计时
unsigned char
Tx_R='R'; //发送字符为R
unsigned char
Rx_R[30]; //接收数组
//如果定义数字较大的数组,需要加入code区,不然显示segment too large
unsigned char
Res_Count; //首次默认是0
uint8
temp;
//**********
//
串口1初始化
*************************/
void UART1_init(void)
//T2作为UART1波特率发生器
{
SCON = 0x50;
//8位数据,可变波特率
AUXR |= 0x40;
//定时器1时钟为Fosc,即1T 11.0592MHz
AUXR &= 0xFE;
//串口1选择定时器1为波特率发生器
TMOD &= 0x0F;
//设定定时器1为16位自动重装方式
TL1 = 0xE0;
//设定定时初值
TH1 = 0xFE;
//设定定时初值
ET1 = 0;
//禁止定时器1中断
TR1 = 1;
//启动定时器1
//以上设置由STC-ISP生成
ES = 1;
// 开串口1中断
EA = 1;
// 开总中断
}
//*
****
**
**
//延迟函数1ms
由STC-ISP生成
**
*
***
*
***
*
***
****
/
void Delay1000us()
//@11.0592
{
unsigned char
i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
//*
****
**
**
串
口1 发送字符函数
**
****
*
***
*
***
*
***
**
/
void SendDataByUart1(uint8 dat)
{
SBUF = dat; //写数据到UART数据寄存器
while(TI == 0);
//在停止位没有发送时,TI为0即一直等待,在函数里循环。
//当TI硬件置1,跳出此循环。
TI = 0; //清除TI位(该位必须软件清零)
}
//串口1 发送字符串函数
void sendcombytes(unsigned char *ptr)
//*ptr指向字符串的首地址,printf打印时直到\0停止。
{
while(*ptr) //*ptr 不为空,一直循环
{
SendDataByUart1(*ptr++);
//TI、RI发送接收中断必须清零,防止出现意外
}
}
//*
****
**
**
串口1 中断服务程序
**************
******
/
void UART1(void) interrupt 4
{
if(TI)
// 发送完成中断
{
TI=0;
flag_T=1; //接收完毕标志,接收一个'R
'
}
if(RI)
// 接收完成中断 RI==1,接收完成一个字节
{
RI=0;
Rx_R[Res_Count] = SBUF;
Res_Count++;
flag_R=1; //接收完成标志位置1
flag_Time=0; //延时计数清零
}
}
//*********写主函数********************/
main()
{
UART1_init();
while(1)
{
unsigned int j=0;
unsigned int k=0;
SendDataByUart1('R');
for(j=0;j<1000;j++)//发完后延迟等待1s,同时等待接收
{
Delay1000us();
}
do{
flag_Time++; // 延时计数器+1
Delay1000us(); //延迟1ms
}while(flag_Time<5);
// 5ms时间到,flag_Time仍未置0,表示5ms没有收到数据。
//相当于空闲等待5ms。
flag_R=0;
// 接收标志清0
Rx_R[Res_Count] ='\0';
//空闲5ms未收到后,表示结束,加结束符。
Res_Count=0; // 接收数据字节计数器清0
sendcombytes(Rx_R);
//向1口发送
for(j=0;j<500;j++)//发完后延迟等待0.5s,同时等待接收
{
Delay1000us();
}
}
}
串口收发如图:可自由输入字符串长度,并打印出来。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
注册哦
x
回复
举报
返回列表
发新帖
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
注册哦
本版积分规则
发表回复
回帖后跳转到最后一页
科慧智控
回复楼主
返回列表
『国外:三菱/西门子/欧姆龙/松下』
『国产:台达/汇川/信捷产品交流区』