串口接收8位16进制数据不会写,求教育。
我想写个串口接收8位,16进制数据的程序,可是完全没头绪啊,特别是到了结束位那里完全不知道怎么判断,这是网上改的程序,求我华夏前辈指点感激不尽#include<reg52.h>
#include<intrins.h>
#define uch unsigned char
#define uint unsigned int
bit receive_flag;//位定义,作为txdata接收到数据的标志
uch rxdata = {0}; //用于存放接收到的字符
uch txdata = {0}; //用于存放将要发送的字符
uch i = 0;
void init() //初始化
{
P1 = 0XFF;
SCON = 0X50;//方式1 8位异步收发,波特率可调
PCON = 0X80;//9600
TMOD = 0X20;//定时器T1,方式2
TCON= 0X40;//即TR1 = 1;开启定时T1
TH1 = 0xfd; //(256 - TH1 = 11059200/12/16/9600)
TL1 = 0XFd; //9600=2^SMOD * 晶振频率/32/12/(256 - TH1)
EA = 1; //总中断开启
ES = 1; //开启串口中断
}
void main()
{
init(); //初始化
while(1)
{
if(rxdata == 0x1c) //如果接收到的字符是1则P1口拉低
{
P1 = 0X06;
}
if(rxdata == 0x10) //如果接收到的字符是1则P1口拉低
{
P1 = 0Xff;
}
if(receive_flag)
{
SBUF = txdata;
while(!TI); //等待数据发送完成
TI = 0; //为下次发送做准备,下同
receive_flag = 0;
}
}
}
void receive() interrupt 4 using 0 //串口中断
{
ES = 0;//防中断坑爹
if(RI) //等待发送
{
RI = 0; //为下次发送做准备
rxdata = SBUF; //读取数据缓冲器的值
txdata = rxdata;//把值移动到要发送的地址
receive_flag = 1; // 表示接收到要发送的值
}
i++;
if(i>=8)
{
i = 0;
}
ES = 1; //开启中断
}
防沉自顶,改动的程序可能改的不好,求高手指教 菜鸟你好,继续努力,帮你顶贴 qiqirachel 发表于 2016-4-21 20:43
菜鸟你好,继续努力,帮你顶贴
谢谢前辈 加油,你行的^_^ 加油,你行的^_^ 醉了,前辈们,真的很头疼,你们要是会就指点我一两句吧,被逗哭了 既然串口开启了中断,TI却不在中断里清零,你这程序是要中断死的节奏{:lol:}{:lol:}{:lol:} LZ去学习一下状态机,接收用状态机来处理,基本思路就是第一个接收的字节判断是否是起始字节,是的话就状态机步进一步,判断第二个接受的字节。。。直到包内容收完判断结束字节,校验和。 好久没看到新手了 51的串口发送和接收是一个中断 看分坛金沙滩的小宋老师的教程,应该有你想要的 yangsen 发表于 2016-4-21 21:34
LZ去学习一下状态机,接收用状态机来处理,基本思路就是第一个接收的字节判断是否是起始字节,是的话就状态 ...
还要加上超时处理的。 可以找些视频看看,看别人讲解一下,很快就知道了。。。{:lol:} ES = 0;//防中断坑爹 挺接地气 kebaojun305 发表于 2016-4-21 23:55
还要加上超时处理的。
没看懂,超时处理是什么{:shocked:} 书里没写啊,我们学校是三本,老师没讲过啊,我很笨的,求前辈不吝再点拨下 我也帮顶一下 柯铭凯 发表于 2016-4-22 10:00
没看懂,超时处理是什么 书里没写啊,我们学校是三本,老师没讲过啊,我很笨的,求前辈不吝再 ...
尽信书不如无书,超时就是你的状态机进入到某个状态后等待一段时间仍没有收到步进到下一步的信号就复位状态机或者转错误处理。贴一段原来写的收数据的程序给你参考,这个不是51的并且不是在中断中处理接收到的数据而是在主循环中检查缓冲区是否有数据要处理,有就把缓冲数据全部取出处理,你可以把判断缓冲是否空的部分去掉直接在中断中调用。我超时设的是200ms。协议帧格式是起始字+数据长度+数据+包校验+包结束字。在收到起始字后启动超时定时,定时结束前不收完所有的数据包内容就复位状态。
#define COM_OVER_TIME 200
unsigned char ucOverTime;
bool PackageStart=FALSE;
void Communication(unsigned char *ucpBuff)
{
static unsigned char ucComState=0;
static unsigned char ucDataLength,ucCmdAnalsys;
unsigned char ucTemp;
static unsigned char ucUartRd; //uart buffer read point
#ifdef DEBUG_SIM
if(PackageStart==TRUE&&ucOverTime==0)ucComState=0; //Over time reset state
#endif
while(ucUartRd!=UART_RX_NUM){ //buffer not empty
switch(ucComState){
case 0: //check start
if(*(ucpBuff+ucUartRd)==STX){
ucComState++;
ucBuff=STX;
ucOverTime=COM_OVER_TIME;
PackageStart=TRUE;
}
break;
case 1: //receive the package length
ucBuff=*(ucpBuff+ucUartRd);
ucComState++;
ucCmdAnalsys=2; //init the data count
ucDataLength=ucBuff;
break;
case 2:
if(ucBuff!=ucCmdAnalsys){
ucBuff=*(ucpBuff+ucUartRd);
ucCmdAnalsys++;
break;
}
else{ //data receive finished
ucComState++;
}
case 3: //check BCC
ucTemp=BCC_PRO(ucBuff,ucDataLength);
if(ucTemp==*(ucpBuff+ucUartRd))
ucComState=4; //receive the package end
else{
ucComState=0;
PackageStart=0;
}
break;
case 4:
ucTemp=*(ucpBuff+ucUartRd);
if(ucTemp==ETX){
ucBtOnlineFlag=TRUE;
Command();
}
ucComState=0;
PackageStart=0;
}
ucUartRd++; //refresh the read counter
ucUartRd=ucUartRd%USART_BUFF;
}
} 本帖最后由 天下乌鸦一般黑 于 2016-4-22 12:33 编辑
头文件。
另一个菜鸟表示提供点思路吧,
我的这个串口可以接收一串数据,带有超时判定功能,数据格式是 :
帧头两个字节 0xf3 0xf4
命令字一个字节
数据域长度一个字节
数据域
#define g_DatRev_size20//接收串口中断数据的缓冲区数组大小
static unsigned int count = 0;//串口接收计数的变量
unsigned int Overtime = 2000; //2ms,超时判定2ms
unsigned char g_DatRev={0};//接收缓存
//-------------------串口初始化----------------------------
void init_uart()
{
SCON = 0x50; //串口方式1, 8-n-1, 允许接收.
TMOD = 0x21; //T1方式2 ,同时配置定时器0,工作方式1
IP =0x10;//把串口中断设置为最高优先级
TH1 = 0xFD; //9600bps@11.0592MHz
TL1 = 0xFD;
IE |= 0x90;
TR1 = 1;
ET0=1; //允许定时中断
ES= 1; //开中断.
EA= 1;
}
//-------------------串口中断函数---------------------------
void UART_INT(void) interrupt 4
{
if(RI==1)
{
RI = 0;
g_DatRev = SBUF;
if(g_DatRev==0xF3&&count==0) {count=1;}//帧头
else if(count==1 && g_DatRev==0xF4) {count=2;}
else if (count==2){Order = g_DatRev ;count=3;}
else if (count==3){DatLgth = g_DatRev;count=4;}
else if(count>=4 && count<(4+DatLgth+2)){count ++;}
else if(count == (DatLgth+4+2)){ES = 0; retFlag = 1;count=0;}
else {count=0;}
resettimer();
}
else {TI = 0;}//如果不是串口接收中断,那么必然是串口发送中断,及时清除发送中断的标志,否则一直发送中断
}
//-------------------判断count不为0的话就启动定时器-------------------------
void resettimer()
{
TR0=0;
TH0=(65536-Overtime)/256;
TL0=(65536-Overtime)%256;
if(count!=0){TR0=1;}
}
主函数main
void main (void)
{
init_uart();
while(1)
{
if(retFlag == 1)
{
//处理接收到的数据
retFlag = 0;
}
}
} 各位大神,我发了个新贴,把刚改好的程序发上去了,问题没执行,统共才100行代码,很简单的拉低电平而已,求大神帮忙看下问题在哪呗
#include <reg51.h>
#define uch unsigned char
#define uint unsigned int
/*=========================================*/
bit com_over;
bit com_ok;
bitT;
uch data com_buf;
uch data com_num=0;
uch data send_num=0;
uch data com_delay;
uch data temp;
void System_init(void)
{
TMOD=0x21;
SCON=0x70;//SM0=0,SM1=1,SM2=1,REN=1,TB8=0,RB8=0,TI=0,RI=0
PCON=0x80;//波特率加倍
TH0=0xb8;//for 11.0592 定时10MS
TL0=0x00;
P1 = 0X00;
TH1=TL1=0xfa; // 9600 for 11.0592
TR0=1;
TR1=1;
ET0=1;
REN=1;
ES=1;
EA=1;
com_over=0;
com_delay=0;
com_num=0;
}
void main(void)
{
System_init();
while(1)
{ if(com_ok)
{
ES=0;
com_ok=0;//表明串口接受数据成功,这里先清标读
//这里可以加一些需要处理的子程序
//下面可以对收到的数据进行处理,这里收到的数据会通过串口发送出去,
//==================================================================================
//这里发送数据采用查询方式来做,
send_num=0;
do
{
temp=com_buf;
SBUF=com_buf;//SBUF赋值后,会自动进入中断去判断有没有发送成功,
while(!TI);//通过TI是不是1来判断
TI=0;
send_num++;
}while(temp!=0x0d);
REN=1;
ES=1;
//==================================================================================
/* //这里发送数据采用中断方式来做,
send_num=0;
ES=1; //开启串口中断
SBUF=com_buf;//SBUF赋值后,会自动进入中断去判断有没有发送成功,
*/
//==================================================================================
}
}
}
void timer0() interrupt 1 //定时器0中断
{
TH0=0xb8; //10ms,11.0592MHz
TL0=0x00;
if(com_over)
{ com_delay++;
if(com_delay>=3)
{ com_delay=0x00;
com_over=0;
com_num=0;
}
}
}
void serial0() interrupt 4
{
if(RI)
{ RI=0;//表示收到数据,这里先清RI
com_over=1;com_delay=0;//开启通信超时
com_buf=SBUF;//把收到数据放进数组里
if(com_buf==0x0d) //判断是不是收到最后一个数据
{ com_over=0;com_delay=0;//串口数据已经收完,关闭通信超时
com_num=0;
REN=0;//关闭串口接受,到主程序里面判断是否还要重新打开
if(com_buf == 0x32)
{
if(com_buf == 0x32)
{
if(com_buf == 0x39)
{
if(com_buf == 0x36)
{
if(com_buf == 0x39)
{
P1 = 0xff;
}
}
}
}
}
com_ok=1;//置数据接受标志
}
else
com_num++;//不是最后一个数据,+1,方便接收下一个数据
}
else if(TI)
{ TI=0;//表示数据已经发送成功,这里先清TI
if(com_buf==0x0d) //数据是不是最后一个字节
{ send_num=0;REN=1;//发送数据完成,开启串口接收
}
else
{ send_num++;//不是最后一个字节,继续发送数据
SBUF=com_buf;
}
}
}
wxdn 发表于 2016-6-10 21:15
为什么不学习MODBUS通讯的方式,后面搞两个校验的,更加好用。
大神,求教程链接
给你说个思路,如果通信协议是ascill 就检测最后的 0x0D 0x0A,如果是十六进制 就以通信速率计算两个数据的时间间隔, 每次收一个清计时器,当超过5个数据时间是认为结束。 snail_dongbin 发表于 2016-6-16 21:31
给你说个思路,如果通信协议是ascill 就检测最后的 0x0D 0x0A,如果是十六进制 就以通信速率计算两个数据的 ...
感觉清晰了一点,谢谢前辈 柯铭凯 发表于 2016-5-1 11:38
各位大神,我发了个新贴,把刚改好的程序发上去了,问题没执行,统共才100行代码,很简单的拉低电平而已, ...
没人原因看这么多行代码,你又是copy的,更是无人理了
页:
[1]