modbus 串口读寄存器中的寄存器和缓冲区有什么区别

关于MCU串口中断接收,以及缓存发送大量数据的问题,高手进
需要利用串口接收DET的大量数据,存于缓存后将数据转发给PC,请问高手怎么做这个中断机制以及如何处理对缓冲区数据的读取比较合适呢?
我的数据一包200个字节,有包头和固定的数据长度。
void REV() interrupt 4
&&if(RI==1)
& & & & {&&
& & & & & & & & ES=0;
& & & & & & & & RI=0;
& & & & & & & & rx_buf=SBUF;
& & & & & & & & if(rx_buf==0xAA)//包头
& & & & & & & & {
& & & & & & & & & & & & i++;
& & & & & & & & & & & & if(i==199)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & revfinish=1;//接收完成 发送
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & else
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & i=0;
& & & & & & & & & & & & }
& & & & & & & & ES=1;
楼上的这种方式不合理吧?
接收计数i要定义成全局或静态变量,而且你这样写包头包尾没起作用,临时写一段,接收计数你测试时注意下,我可能数错了--!
#define&&REC_MAX& &200
#define&&CHECK_HEAD&&0xFF  & && & //&&随便定义的包头
#define&&CHECK_TAIL&&0xF0
volatile uchar Rec_L  & && & //&&接收计数
volatile uchar Rec_F & && &&&//&&接收标志
xdata& & uchar DataBuf[REC_MAX]; // 缓存
void Initial_Serial(void) & && & // 串口初始化
& & Rec_Len&&= 0;     & && & // 初始接收长度为0
& & Rec_Flag = 0;     & && & // 未接收 0 未接收或接收完成 1 开始接收
void Uart_Rec(void)   interrupt 4
& & if(RI)
& && &&&RI = 0;
& && &&&sbuffer = SBUF;
& && &&&if((sbuffer == CHECK_HEAD) && (Rec_Flag == 0))  // 如果收到文件头而且当前未接收
& && && && &Rec_Flag = 1;
& && && && &Rec_Len&&= 0;
& && && && &DataBuf[0] =      & && && & // 这里保留了包头
& && &&&}& &
& && &&&else if(Rec_Flag)&&  & && && && && && && && &// 开始接收
& && && && &if(Rec_Len & (REC_MAX - 1))&&
& && && && &{
& && && && && & Rec_Len++;
& && && && && & DataBuf[Rec_Len] =&&     // 当数据送缓冲区
& && && && &}
& && && && &else if(Rec_Len == (REC_MAX - 1))    &&//&&接收完成 
& && && && &{
        if(DataBuf[Rec_Len] == CHECK_TAIL)
& && && && && & {
& && && && && && &&&....& && && &//&&表明接收成功未出错
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&....& && && &//&&有误码
& && && && && & }
& && && && && & Rec_Flag = 0;  // 接收完成,标志清0
& && && && &}
真难对齐....
忘加注释了--!,给你加上,哥人品一向很好,代码临时写的你测试下,大致思路是这样的。
好像写的有点长
楼主的代码有问题
&&1.中断里只负责将寄存器的值转存到缓存中
&&2.如有必要,可以在中断里判断包头和包未,设置相应标志,处理则应该交由主程序处理
下面仅供参考...
(原文件名:c790eb49.JPG)
不好意思,抗震救灾刚回来,有劳楼上诸位了。
amazing030 兄弟的程序结构很严谨,不过没有置发送标志位吧,然而这种接受和发送方式适合每包数据200bytes的数据传输么?可否将主程序里的发送机制也做出来呢?也好让鄙人能理解您的思路。
谢谢martal的建议。
不太明白security 的超时等待什么意思,我只是想接收数据放缓存,接受完毕调用,然后清空。
希望还能得到诸位的答复,谢谢。
我是菜鸟,也正在学习正在学习这种编程思想,谢谢各位的指点!
那段代码只是我临时写的,只是大致思路而路。
1.判断出包头
 这里由接收完成标志Rec_Flag确认,Rec_Flag未接收/接收完成时置0,当Rec_Flag为0且接收字符为包头时开始接收,若Rec_Flag为1则表明接收的为数据,这是为了防止包头和接收数据相同时判断错误。
2.接收计数 
 这里由接收计数变量Rec_Len确认,在未接收到校验尾/包尾时计数
3.判断包尾/检验
 当接收Rec_Len溢出时(即接收到指定长度数据),如果最后一位数据与包尾相同则表明接收成功。一般包尾只是判断接收完成,还有一位用来判断接收成功与否,即校验位,需对所接收的数据进行校验计算,如非必要最好不要在中断中进行。只有校验成功(有别于接收成功)才可对数据进行目标操作。
数据长短这个只是怕传输出错,和处理关系不大,但最好有检验位。也可拆成几段短的数据发送。
TI可以不置位,因为没给发送SBUF装值,你不放心的话再加上一段
& & if(TI)
& && &&&TI = 0;
以上只是个人的拙见,欢迎拍砖,共同提高
另外,对自称哥表示歉意,本人88年的..只是最近网上哥太多
回复【6楼】renjun861214
不好意思,抗震救灾刚回来,有劳楼上诸位了。
amazing030 兄弟的程序结构很严谨,不过没有置发送标志位吧,然而这种接受和发送方式适合每包数据200bytes的数据传输么?可否将主程序里的发送机制也做出来呢?也好让鄙人能理解您的思路。
谢谢martal的建议。
不太明白security 的超时等待什么意思,我只是想接收数据放缓存,接受完毕调用,然后清空。
希望还能得到诸位的答复,谢谢。
-----------------------------------------------------------------------
关于5楼的 程序伪代码,适用在有额外空闲定时器的情况,你可以在主进程中,分析协议,然后再发送。
这里关于 程序伪代码 中的超时等待,我从Win32 串口驱动,引申说明下原理:
Win32 串口操作涉及到的超时数据结构
typedef& &struct& &_COMMTIMEOUTS& &{& &&&
& && &DWORD& &ReadIntervalT& && && & //& &读间隔超时& &
& && &DWORD& &ReadTotalTimeoutM& &//& &读时间系数& &
& && &DWORD& &ReadTotalTimeoutC& &&&//& &读时间常量& &
& && &DWORD& &WriteTotalTimeoutM&&//& &写时间系数& &
& && &DWORD& &WriteTotalTimeoutC& & //& &写时间常量& &
&&} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
具体各个成员的含义,可以百度下,会有较详细的介绍的。
我这里只是想 着重 点出 ReadIntervalTimeout,这里实际跟 5楼的 程序伪代码 说到超时是一样。
即:ReadIntervalTimeout 指在接收时两个字符之间的最大延时,一旦连续的两个字符传输的时间差超过ReadIntervalTimeout该值,将发生超时,返回已经接受到缓冲的数据,这时系统再对该数据进行解析,处理。
用个环形缓冲区会不会好点呢,一定要打包在一起吗?
本人多年来一直用的都是amazing030兄弟的差不多的思路,简单易理解,呵呵
回复【9楼】amazing030
-----------------------------------------------------------------------
老兄,加个QQ,我想咨询一下这方面的问题。。谢谢了
回复【8楼】amazing030&&
-----------------------------------------------------------------------
回复【楼主位】renjun861214&&
-----------------------------------------------------------------------
网络上有很多参考,你可以看看77e58双串口的参考代码。最简单有效的是在内存中开辟数据池,中断函数只负责收发数据,不做任何判断。形象点说就是中断函数就是水池进水、出水阀门,其他一概不管。数据的提取通过其他函数完成。
再贴上一段环链方式处理的,就是楼上所说的这样。但有时实时要求高的不怎么适用。因为我定的这个协议长度不固定,每收到一个数据都要判断....
#include& & &includes.h&
/**************************** 发送指令格式 *************************************
帧格式: 帧头&&接收方地址&&发送方地址&&帧长&&命令字&&数据域 校验和
字节数:&&2& && && &1& && && &&&1& && &&&1& && &1& && & N& && &1
帧头:& && &两个特殊字节 0x55 0xAA
接收方地址:通讯对象地址
发送方地址:通讯主机地址 / 为分机之间可通讯扩展
帧长:& && &从 命令 到 校验和 的字节数 不包含校验和 为 N + 1
命令字:& & 操作内容
数据域:& & 命令相关数据
校验和:& & 命令字 与 数据域 的算术和
/**************************** 返回指令格式 *************************************
09/14测试通过
#define& &&&SELF_ADDR& && & 0x03
#define& &&&TXD_MAX& && && &32
#define& &&&RCV_MAX& && && &32
#define& &&&GET_CONNECT& &&&0x00& & // 0号命令用于检测设备连接 分机接收到此命令则返回特定命令以示连接
#define& &&&READ_ADDR& && & 0x01& & // 1号命令用于读取设备的编号&&只能一对一识别设备时使用 否则无效
#define& &&&READ_CUR& && &&&0x02& & // 2号命令用于读取指定设备电流
#define& &&&READ_VOL& && &&&0x03& & // 3号命令用于读取指定设备电压
volatile INT8U& &TxdBuf[TXD_MAX];& &// 发送缓存
INT8U& & TxdP& && && && && && &&&// 发送指针 指向将要发送的字节
INT8U& & TxdC& && && && && && &&&// 发送字节计数
volatile INT8U&&RcvBuf[RCV_MAX];& & // 接收缓存
volatile INT8U&&SaveP& && && && &// 接收存储指针
volatile INT8U&&GetP& && && && & // 接收缓存读取指针
volatile INT8U&&StartP& && && &&&// 识别出命令字对应的指针
volatile INT8U&&EndP& && && && & // 根据帧长计算出帧结束地址
INT8U& & DataL
BOOLEAN&&R& && && && && && &&&// 串口收到一个字节标志,为减少变量交互。
BOOLEAN&&StartR& && && && && && &// 开始接收数据帧标志& && && && && && && && && && &
void Device_Init(void)
& & SavePtr = 0;
& & GetPtr&&= 0;
& & Rcvbit&&= 0;
& & StartRcv= 0;
& && && && && && && && && && && && && &
void ISR_Uart0(void)& & interrupt 4
& & if(RI0)
& && &&&RI0 = 0;
& && &&&RcvBuf[SavePtr] = SBUF0;
& && &&&SavePtr = (SavePtr + 1) & (RCV_MAX - 1);
& && &&&Rcvbit = 1;
& & if(TI0)
& && &&&TI0 = 0;
& && &&&TxdCnt--;
& && &&&if(TxdCnt & 0)
& && && && &TxdPtr++;
& && && && &SBUF0 = TxdBuf[TxdPtr];
BOOLEAN Cmd_Adjust(void)
& & INT8U i, j,
& & BOOLEAN flag = 0;
& & while(GetPtr != SavePtr)
& && &&&if(!StartRcv)
& && && && &k = 0;
& && && && &
& && && && &i = (GetPtr - 5) & (RCV_MAX - 1);
& && && && &if(RcvBuf == 0x55)
& && && && && & k++;
& && && && &i = (GetPtr - 4) & (RCV_MAX - 1);
& && && && &if(RcvBuf == 0xAA)
& && && && && & k++;
& && && && &i = (GetPtr - 3) & (RCV_MAX - 1);
& && && && &if(RcvBuf == SELF_ADDR)
& && && && && & k++;
& && && && &if(k == 3)
& && && && &{
& && && && && & StartRcv = 1;
& && && && && & i = (GetPtr - 1) & (RCV_MAX - 1);
& && && && && & DataLen = RcvBuf;
& && && && && & StartPtr = GetP
& && && && && & EndPtr = (GetPtr + DataLen) & (RCV_MAX - 1);
& && && && &}
& && &&&else& & //开始接收数据处理
& && && && &if(GetPtr == EndPtr)
& && && && &{
& && && && && & StartRcv = 0;& &// 数据帧接收完成
& && && && && & j = StartP
& && && && && & k = 0;
& && && && && & for(i = 0; i & DataL i++)& && &&&// 计算校验和
& && && && && & {& && &
& && && && && && &&&k += RcvBuf[j];
& && && && && && &&&j = (j + 1) & (RCV_MAX - 1);
& && && && && & }
& && && && && & k = ~k;
& && && && && & if(k == RcvBuf[j])
& && && && && && &&&flag = 1;
& && && && &}
& && &&&GetPtr = (GetPtr + 1) & (RCV_MAX - 1);
void Deal_Cmd(void)
& & cmd = RcvBuf[StartPtr];
& & switch(cmd)
& && &&&case GET_CONNECT:
& && && && &Display_String(40, 2, &Connect..&, ASC_6x8,&&0);
& && && && && && && &
& && &&&case READ_ADDR:
& && && && &Display_String(40, 2, &Read Addr&, ASC_6x8,&&0);
& && && && &
& && &&&case READ_CUR:
& && && && &Display_String(40, 2, &Read Cur &, ASC_6x8,&&0);
& && && && &
& && &&&case READ_VOL:
& && && && &Display_String(40, 2, &Read Vol &, ASC_6x8,&&0);& && && && &
& && && && &
& && &&&default:
& && && && &
索性再贴一段
//-------------- 串口1接收中断&&我用的是C ---------------//
void Uart1_Interrupt (void) interrupt 20
& & if ((SCON1 & 0x01) == 0x01)& &&&// RI1 = 1;
& && &&&SCON1&&&= 0xFE;& && && && & // RI1 = 0;
& && &&&TR0 = 0;& && && && && && &&&// 关闭定时器
& && &&&Uart1_RcvBuf[Uart1_SavePtr++] = SBUF1;
& && &&&TH0 = 0x28;& && && && && &&&// 这里设置超时时间 视波特率及通信方式而定 别按我的这个设定。。。单片机也不一样。。。
& && &&&TL0 = 0x00;& &&&
& && &&&TR0 = 1;& && && && && && &&&// 开启定时器
& & if((SCON1 & 0x02) == 0x02)& && && && && && && & // Check if transmit flag is set
& && &&&SCON1 = (SCON1 & 0xFD);
//---------------------- 定时器中断 --------------------------//
void ISR_Timer0(void)& &interrupt 1
& & TR0 = 0;& && &&&// 关闭计数
& & LED = !LED;
& & Rcvbit = 1;& &&&// 置接收标志位
& & //TH0 = 0x28;& &//
& & //TL0 = 0x00;
& & //TR0 = 1;& && &// 这里不使能 装值可在这里重装 保证一次接收后才置一次接收位
把我写的GPS接收函数也一并贴出来.....用超时处理的方式处理GPS数据很好使,因为GPS数据每一秒发送一次,每次有大概400Byte的数据,开辟一个缓冲区后等待超时后再处理,9600bps下每秒
9600bit = 1200Byte(实际1000左右) 传送完需大概1/3秒的时间,剩下就是处理和调度的时间了,用51RAM大一些的话也能很好的处理完而不用在中断中处理那么一大堆处理。
typedef struct
& & INT8U B
& & INT8U BlockI
& & INT8U UTCTime[10];& && &// hhmmss.mmm
& & INT8U S& && && &&&// A- 有效定位 V-无效定位
& & INT8U Latitude[9];& && &// ddmm.mmmm
& & INT8U NS;& && && && && &// N/S
& & INT8U Longitude[10];& & // dddmm.mmmm
& & INT8U EW;& && && && && &// E/W
& & INT8U Speed[5];& && && &// 速率000.0~999.9节
& & INT8U Course[5];& && &&&// 航向000.0~359.9度
& & INT8U UTCDate[6];& && & // ddmmyy
}stru_GPSRMC;
typedef struct
& & INT8U B& && && && &
& & INT8U BlockI
& & //INT8U UTCTime[10];& & // hhmmss.mmm RMC中已有, 所以不解析
& & //INT8U Latitude[9];& & // ddmm.mmmm
& & //INT8U NS;& && && && & // N/S
& & //INT8U Longitude[10];&&// dddmm.mmmm
& & //INT8U EW;& && && && & // E/W
& & INT8U PositionF& && &// 0,1,2,6
& & INT8U SateUsed[2];& && &// 00~12
& & //INT8U HDOP[4];& && &&&// 0.5~99.9
& & INT8U Altitude[7];& && &// -99.9
}stru_GPSGGA;
typedef struct
& & INT8U B
& & INT8U BlockI
& & INT8U M& && && && & // A-自动 /M-手动&&
& & INT8U Mode2;& && && && &// 0,1,2,3
& & INT8U SateUsed[12][2];& && && &
& & INT8U PDOP[4];
& & INT8U HDOP[4];
& & INT8U VDOP[4];
}stru_GPSGSA;
typedef struct
& & INT8U SatelliteID[2];& &// 卫星编号
& & INT8U Elevation[2];& &&&// 0-90 degree&&// 不显示GPS卫星的方位图, 所以不解析, 节省 5*12 RAM
& & INT8U Azimuth[3];& && & // 0-359 degree // 需要解析时去除注释'//'和解析前的'//'即可
& & INT8U SNR[2];& && && &&&// 0-99 dbHz
}stru_SatelliteI
typedef struct
& & INT8U B
& & INT8U BlockI
& & INT8U SateInView[2];
& & INT8U GSVID;& && && && &//当前 GSV语句编号
& & stru_SatelliteInfo SatelliteInfo[12];
}stru_GPSGSV;
INT8U GPRMC_Receive(void)
& & INT8U buf[13];
& & INT8U *
& & INT16U
& & memset(&GPS_RMC_Data, 0x00, sizeof(GPS_RMC_Data));&&// 每次处理前将结构体清零
& & index = Find_Str(Uart1_RcvBuf, &$GPRMC,&);
& & if(index)
& && &&&ptr = Uart1_RcvBuf&&+ index + 6;
& && &&&do
& && && && &sbuf = *ptr++;
& && && && &switch(sbuf)
& && && && &{
& && && && && & case ',':& && & // 接收到数据段分隔符','& && && && && && && && && &
& && && && && && &&&GPS_RMC_Data.Block++;& && && && && && & // 数据段标志
& && && && && && &&&GPS_RMC_Data.BlockIndex = 0;& && && && &// 数据段数据计数指针
& && && && && && &&&
& && && && && & default:& && &&&// 接收到数据
& && && && && && &&&switch(GPS_RMC_Data.Block)
& && && && && && &&&{
& && && && && && && && &case 0:&&GPS_RMC_Data.UTCTime[GPS_RMC_Data.BlockIndex] =&&
& && && && && && && && &case 1:&&GPS_RMC_Data.Status =& && && && && && && && && &
& && && && && && && && &case 2:&&GPS_RMC_Data.Latitude[GPS_RMC_Data.BlockIndex] =
& && && && && && && && &case 3:&&GPS_RMC_Data.NS =& && && && && && && && && && &&&
& && && && && && && && &case 4:&&GPS_RMC_Data.Longitude[GPS_RMC_Data.BlockIndex] =
& && && && && && && && &case 5:&&GPS_RMC_Data.EW =& && && && && && && && && && &&&
& && && && && && && && &case 6:&&GPS_RMC_Data.Speed[GPS_RMC_Data.BlockIndex] =& &
& && && && && && && && &case 7:&&GPS_RMC_Data.Course[GPS_RMC_Data.BlockIndex] =& &
& && && && && && && && &case 8:&&GPS_RMC_Data.UTCDate[GPS_RMC_Data.BlockIndex] =&&
& && && && && && && && &default:
& && && && && && &&&}& && && &
& && && && && && &&&GPS_RMC_Data.BlockIndex++;
& && && && && && &&&
& && && && &}
& && &&&}while(sbuf != '*');
& && &&&memset(buf, 0x00, sizeof(buf));
& && &&&buf[0] = GPS_RMC_Data.NS;
& && &&&buf[1] = ' ';
& && &&&buf[2] = ' ';
& && &&&memcpy(buf + 3, &GPS_RMC_Data.Latitude, 9);
& && &&&LCD_ShowString(8, 20, buf, 0);
& && &&&memset(buf, 0x00, sizeof(buf));
& && &&&buf[0] = GPS_RMC_Data.EW;
& && &&&buf[1] = ' ';
& && &&&memcpy(buf + 2, &GPS_RMC_Data.Longitude, 10);
& && &&&LCD_ShowString(120, 20, buf, 0);
& && &&&memset(buf, 0x00, sizeof(buf));
& && &&&buf[0] = 'T';
& && &&&buf[1] = ' ';
& && &&&memcpy(buf + 2, &GPS_RMC_Data.UTCTime, 10);
& && &&&LCD_ShowString(8, 40, buf, 0);
& && &&&memset(buf, 0x00, sizeof(buf));
& && &&&buf[0] = 'S';
& && &&&buf[1] = ' ';
& && &&&memcpy(buf + 2, &GPS_RMC_Data.Speed, 5);
& && &&&LCD_ShowString(8,100, buf, 0);
& && &&&memset(buf, 0x00, sizeof(buf));
& && &&&buf[0] = 'C';
& && &&&buf[1] = ' ';
& && &&&memcpy(buf + 2, &GPS_RMC_Data.Course, 5);
& && &&&LCD_ShowString(8,120, buf, 0);
& & return 0;
INT8U GPGSV_Receive(void)
& & INT8U buf[8] = &Sat: 00&;
& & INT8U i,
& & INT8U *
& & INT16U
& & memset(&GPS_GSV_Data, 0x00, sizeof(GPS_GSV_Data));&&// 每次处理前将结构体清零& &
& & index = Find_Str(Uart1_RcvBuf, &$GPGSV,&);
& & if(index)
& && &&&ptr = Uart1_RcvBuf&&+ index + 6;
& && &&&do
& && && && &sbuf = *ptr++;
& && && && &switch(sbuf)
& && && && &{
& && && && && & case ',':
& && && && && && &&&GPS_GSV_Data.Block++;
& && && && && && &&&GPS_GSV_Data.BlockIndex=0;
& && && && && && &&&
& && && && && & default:& &&&
& && && && && && &&&switch(GPS_GSV_Data.Block)
& && && && && && &&&{
& && && && && && && && &case 1:& &&&//当前GPFSV语句的序号, 该序号计算出该组卫星数据应该存放于数组的哪个位置
& && && && && && && && && & GPS_GSV_Data.GSVID = sbuf - '1';& && && &
& && && && && && && && && &
& && && && && && && && &case 2:
& && && && && && && && && & GPS_GSV_Data.SateInView[GPS_GSV_Data.BlockIndex] =
& && && && && && && && && &
& && && && && && && && &case 3:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4].SatelliteID[GPS_GSV_Data.BlockIndex] =
& && && && && && && && && &
& && && && && && && && &case 4:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4].Elevation[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 5:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4].Azimuth[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 6:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4].SNR[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 7:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+1].SatelliteID[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 8:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+1].Elevation[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 9:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+1].Azimuth[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 10:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+1].SNR[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 11:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+2].SatelliteID[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 12:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+2].Elevation[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 13:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+2].Azimuth[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 14:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+2].SNR[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 15:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+3].SatelliteID[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 16:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+3].Elevation[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 17:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+3].Azimuth[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &case 18:
& && && && && && && && && & GPS_GSV_Data.SatelliteInfo[GPS_GSV_Data.GSVID*4+3].SNR[GPS_GSV_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && &&&}
& && && && && && &&&GPS_GSV_Data.BlockIndex++;
& && && && && && &&&
& && && && &}
& && &&&}while(sbuf != '*');
& && &&&for(i = 0; i & 4; i++)
& && &&&//memcpy(buf + 5, &GPS_GSV_Data.SateInView, 2);
& && &&&//LCD_ShowString(8, 60, buf, 0);
& & return 0;
INT8U GPGGA_Receive(void)
& & INT8U *
& & INT16U
& & memset(&GPS_GGA_Data, 0x00, sizeof(GPS_GGA_Data));&&// 每次处理前将结构体清零& &
& & index = Find_Str(Uart1_RcvBuf, &$GPGGA,&);
& & if(index)
& && &&&ptr = Uart1_RcvBuf&&+ index + 6;
& && &&&do
& && && && &sbuf = *ptr++;
& && && && &switch(sbuf)
& && && && &{&&
& && && && && & case ',':& && &&&// 该字段结束, 下一个
& && && && && && &&&GPS_GGA_Data.Block++;
& && && && && && &&&GPS_GGA_Data.BlockIndex = 0;& && && && && & //字段索引置0:第一个字符
& && && && && && &&&
& && && && && & default:& && &&&// 字段字符& && && && && && && && &
& && && && && && &&&switch(GPS_GGA_Data.Block)&&//判断当前处于哪个字段
& && && && && && &&&{& && && && && &
& && && && && && && && &//case 0:
& && && && && && && && && & //GPS_GGA_Data.UTCTime[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && & //
& && && && && && && && &//case 1:
& && && && && && && && && & //GPS_GGA_Data.Latitude[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && & //
& && && && && && && && &//case 2:
& && && && && && && && && & //GPS_GGA_Data.NS=
& && && && && && && && && & //
& && && && && && && && &//case 3:
& && && && && && && && && & //GPS_GGA_Data.Longitude[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && & //
& && && && && && && && &//case 4:
& && && && && && && && && & //GPS_GGA_Data.EW=
& && && && && && && && && & //
& && && && && && && && &case 5:
& && && && && && && && && & GPS_GGA_Data.PositionFix=
& && && && && && && && && &
& && && && && && && && &case 6:
& && && && && && && && && & GPS_GGA_Data.SateUsed[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && && && &//case 7:
& && && && && && && && && & //GPS_GGA_Data.HDOP[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && & //
& && && && && && && && &case 8:
& && && && && && && && && & GPS_GGA_Data.Altitude[GPS_GGA_Data.BlockIndex]=
& && && && && && && && && &
& && && && && && &&&}& && && &
& && && && && && &&&GPS_GSV_Data.BlockIndex++;& &//字段索引++, 指向下一个字符&&
& && && && && && &&&
& && && && &}
& && &&&}while(sbuf != '*');
& & return 0;
INT8U GPGSA_Receive(void)
& & INT8U *
& & INT16U
& & memset(&GPS_GSA_Data, 0x00, sizeof(GPS_GSA_Data));&&// 每次处理前将结构体清零& &
& & index = Find_Str(Uart1_RcvBuf, &$GPGSA,&);
& & if(index)
& && &&&ptr = Uart1_RcvBuf&&+ index + 6;
& && &&&do
& && && && &sbuf = *ptr++;
& && && && &switch(sbuf)
& && && && &{
& && && && && & case ',':
& && && && && && &&&GPS_GSA_Data.Block++;
& && && && && && &&&GPS_GSA_Data.BlockIndex=0;&&
& && && && && && &&&&&
& && && && && & default:
& && && && && && &&&switch(GPS_GSA_Data.Block)&&
& && && && && && &&&{
& && && && && && && && &case 0:
& && && && && && && && && & GPS_GSA_Data.Mode =& &
& && && && && && && && && &&&
& && && && && && && && &case 1:
& && && && && && && && && & GPS_GSA_Data.Mode2 =
& && && && && && && && && &&&
& && && && && && && && &case 2:
& && && && && && && && &case 3:
& && && && && && && && &case 4:
& && && && && && && && &case 5:
& && && && && && && && &case 6:
& && && && && && && && &case 7:
& && && && && && && && &case 8:
& && && && && && && && &case 9:
& && && && && && && && &case 10:
& && && && && && && && &case 11:
& && && && && && && && &case 12:
& && && && && && && && &case 13:& && &&&//2-13 是已使用的卫星ID, 保存于数组中
& && && && && && && && && & GPS_GSA_Data.SateUsed[GPS_GSA_Data.Block-2][GPS_GSA_Data.BlockIndex]=&&
& && && && && && && && && &&&
& && && && && && && && &case 14:
& && && && && && && && && & GPS_GSA_Data.PDOP[GPS_GSA_Data.BlockIndex]=
& && && && && && && && && &&&
& && && && && && && && &case 15:
& && && && && && && && && & GPS_GSA_Data.HDOP[GPS_GSA_Data.BlockIndex]=
& && && && && && && && && &&&
& && && && && && && && &case 16:
& && && && && && && && && & GPS_GSA_Data.VDOP[GPS_GSA_Data.BlockIndex]=
& && && && && && && && && &&&
& && && && && && &&&}& && && &
& && && && && && &&&GPS_GSV_Data.BlockIndex++;& &//字段索引++, 指向下一个字符&&
& && && && && && &&&
& && && && &}
& && &&&}while(sbuf != '*');
& & return 0;
对于RAM不大的单片机,如果只接收部分数据包的话可按下面的
/************************************************************************
AS1_RcvState:& &0 接收挂起状态 等待接收到'$'才动作
& && && && && & 1 接收数据头并判断 如为&$GPRMC&则为2
& && && && && & 2 判断成功 开始接收数据包 接收到'*'后为3
& && && && && & 3 接收完成 等待超时后处理 同时清0返回挂起状态等待下一次接收
*************************************************************************/
ISR(AS1_InterruptRx)
& & byte OnFlags = 0x00;& && && && && &&&// Temporary variable for flags
& & byte StatReg = SCIS1;& && && && && & // Temporary variable for status flags
& & AS1_TComData Data = SCID;& && && && &// Read data from the receiver into temporary variable for data
& & //setReg8(MTIMSC, 0x10);& && && && & // 关闭定时器 Stop timer&&
& & setReg8(TPMSC, 0x00);& && && && && & /* Stop HW; disable overflow interrupt and set prescaler to 0 */
& & if (AS1_InpLen & AS1_INP_BUF_SIZE)
& & {& &&&
& && &&&if(Data == '$' && AS1_RcvState != 3)
& && && && &AS1_InpLen = 0;
& && && && &AS1_RcvState = 1;
& && &&&if(AS1_RcvState == 1)
& && && && &AS1_InpBuffer[AS1_InpLen++] = D& &
& && && && &if(AS1_InpLen == 6)
& && && && &{& &//-------------- 这里不用比较字符串的方式 需要哪个数据包就换相关的字符
& && && && && & if(AS1_InpBuffer[1] == 'G' && AS1_InpBuffer[2] == 'P' && AS1_InpBuffer[3] == 'R' \
& && && && && & && AS1_InpBuffer[4] == 'M' && AS1_InpBuffer[5] == 'C')
& && && && && & {
& && && && && && &&&AS1_RcvState = 2;& &
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&AS1_RcvState = 0;& && & // 返回0状态等待接收
& && && && && & }
& && && && &}
& && &&&else if(AS1_RcvState == 2)
& && && && &AS1_InpBuffer[AS1_InpLen++] = D&&
& && && && &if(Data == '*')
& && && && &{
& && && && && & //AS1_Rcvbit = 1;
& && && && && & AS1_RcvState = 3;& &// 状态3是为防止此次数据帧再次接收到'$'后破坏数据结构
& && && && && & AS1_InpLen = 0;&&
& && && && &}
& && &&&SerFlag |= FULL_RX;& && && && && & // If yes then set flag buffer overflow
& && &&&OnFlags |= ON_ERROR;& && && && && &// Set flag &OnError&& && && &
&&/* TPMSC: TOF=0,TOIE=0,CPWMS=0,CLKSB=0,CLKSA=0,PS2=0,PS1=0,PS0=0 */
&&//setReg8(TPMSC, 0x00);& && && && && & /* Stop HW; disable overflow interrupt and set prescaler to 0 */
&&/* TPMC0SC: CH0F=0,CH0IE=1,MS0B=0,MS0A=1,ELS0B=0,ELS0A=0,??=0,??=0 */
&&//setReg8(TPMC0SC, 0x50);& && && && &&&/* Set output compare mode and enable compare interrupt */
&&TTicks = 0;& && && && && && && && &&&/* Counter of timer ticks */
&&//TOvf = FALSE;& && && && && && && && &/* Counter overflow flag */
&&FC161_SetCV(0xFEFFU);& && && && && & /* Inicialize appropriate value to the compare/modulo/reload register */
&&setReg8(TPMCNTH, 0x00);& && && && &&&/* Reset HW Counter */
&&setReg8(TPMSC, 0x0A);& && && && && & /* Set prescaler and run counter */
& & //------- 启动定时器并重新装值等待超时溢出 32ms& &
& & TTicks = 0;& && && && && && && && &&&// Counter of timer ticks
& & // TOvf = FALSE;& && && && && && && &// Counter overflow flag
& & FC161_SetCV(0xFE);& && && && && && & // Inicialize appropriate value to the compare/modulo/reload register
& & // setReg8(MTIMCLK, 0x11);& && && &&&// Set clock-source and prescaler&&
& & setReg8(MTIMSC, 0x60);& && && && && &// Reset HW Counter and run timer&&
上面是用的Freescale的单片机
这个是我改写的比较字符串的函数,注意返回的是偏移量
INT16U Find_Str(INT8U *str, INT8U *ptr)
& & & & INT16U index = 0;
& & & & INT8U *s_& && &
& & & & INT8U *m_& && &
& & & & INT8U *t_
& & & && &&&
& & & & if(str == 0 || ptr == 0)
& & & && &&&return 0;
& & & & for(s_temp = *s_temp != '\0'; s_temp++)
& & & & & & & & index++;
& & & & & & & & m_temp = s_
& & & & & & & & for(t_temp = *t_temp == *m_ t_temp++, m_temp++){&&};
& & & & & & & & if(*t_temp == '\0')
& & & & & & & & & & & &
& & & & return 0;
第一种可能大家不屑,但对于通信间隔不定的话还是比较实用,因为超时也不一定见效
第二种是环链型处理的,可能某些场合适用
第三种的话比较常用,但如果从机(主机)有应答的话,可不用定时器,加几十ms延时就OK
好,太强了!做个记号!
单片机串口接收数据的一点建议:对于有格式需要判断包头包尾的数据包,一定要做个接收超时处理,不然一个包出错,可能将导致以后所有的包全都收不到。
正好有相关的问题,学习了,非常感谢分享
回复【楼主位】renjun861214
-----------------------------------------------------------------------
可以这样,把所有数据接收到缓存数组里(这样中断函数里程序很少),然后根据调度器再写个处理函数定时检查缓存数组里的数据就ok了吧~
void Tx_Rx_0_Update(void) interrupt INTERRUPT_UART_0_Rx_Tx
& & & & if(RI0)
& & & & & & & & RI0 = 0;//清中断标志
& & & & & & & & UART0_Rx_Buffer[UART0_Rx_Buffer_In++]= SBUF0;//接收数据
& & & & & & & & if(UART0_Rx_Buffer_In == UART0_Rx_Buffer_MAX)//循环数组,如果数据量又大又快,可以把数组定义大一些。
& & & & & & & & {
& & & & & & & & & & & & UART0_Rx_Buffer_In = 0;
& & & & & & & & }
& & & & if(TI0)
& & & & & & & & if(UART0_Tx_Buffer_Out != UART0_Tx_Buffer_In)//首尾不相等,这个数组也要定义大些,使cpu能处理过来,保证不溢出
& & & & & & & & {
& & & & & & & & & & & & SBUF0 = UART0_Tx_Buffer[UART0_Tx_Buffer_Out++];//发送数组数据
& & & & & & & & & & & & if(UART0_Tx_Buffer_Out == UART0_Tx_Buffer_MAX)//循环数组
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & UART0_Tx_Buffer_Out = 0;
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & else
& & & & & & & & {
& & & & & & & & & & & & TI0 = 0;//关中断标志
& & & & & & & & }
数据都写在数组里,想发送的时候TI0 = 1;就ok了
学习了呵呵
谢谢..学习了
很好,看到了那个双串口
支持双串口的77E58程序
#include &W77E58.h&
#include &Const.h&
#include &CRC8.h&
bit fSeri0_Send_Ok;
bit fSeri1_Send_Ok;
bit fSeri1_O
/**************************************************
**************************************************/
unsigned char xdata xBuf_Send_0[XBUFSERIAL0SEND];
unsigned char xdata xBuf_Reci_0[XBUFSERIAL0RECI];
unsigned char xdata *Seri0_ReadSendPoint=xBuf_Send_0;
unsigned char xdata *Seri0_WriteSendPoint=xBuf_Send_0;
unsigned char data Seri0_SendN
unsigned char xdata *Seri0_ReadReciPoint=xBuf_Reci_0;
unsigned char xdata *Seri0_WriteReciPoint=xBuf_Reci_0;
unsigned int data Seri0_ReciN
/**************************************************
压入单数据串口0发送队列
**************************************************/
void Seri0_PushSend(unsigned char mData)
*Seri0_WriteSendPoint=mD
if(Seri0_WriteSendPoint==(xBuf_Send_0+XBUFSERIAL0SEND-1))
Seri0_WriteSendPoint=xBuf_Send_0;
else Seri0_WriteSendPoint++;
Seri0_SendNum++;
if(fSeri0_Send_Ok==0){fSeri0_Send_Ok=1;TI=1;}
/**************************************************
弹出串口0接收队列单数据
**************************************************/
unsigned char Seri0_PopReci()
i=*Seri0_ReadReciP
if(Seri0_ReadReciPoint==(xBuf_Reci_0+XBUFSERIAL0RECI-1))
Seri0_ReadReciPoint=xBuf_Reci_0;
else Seri0_ReadReciPoint++;
Seri0_ReciNum--;
/**************************************************
读出串口0接收队列指定序号数据
**************************************************/
unsigned char Seri0_ReadReci(unsigned char mId)
unsigned char xdata *pT
pTemp=Seri0_ReadReciPoint+mId;
if(pTemp&(xBuf_Reci_0+XBUFSERIAL0RECI))return(*pTemp);
else return(*(pTemp-XBUFSERIAL0RECI));
/**************************************************
**************************************************/
unsigned char xdata xBuf_Send_1[XBUFSERIAL1SEND];
unsigned char xdata xBuf_Reci_1[XBUFSERIAL1RECI];
unsigned char xdata *Seri1_ReadSendPoint=xBuf_Send_1;
unsigned char xdata *Seri1_WriteSendPoint=xBuf_Send_1;
unsigned int data Seri1_SendN
unsigned char xdata *Seri1_ReadReciPoint=xBuf_Reci_1;
unsigned char xdata *Seri1_WriteReciPoint=xBuf_Reci_1;
unsigned char data Seri1_ReciN
/**************************************************
压入单数据串口1发送队列
**************************************************/
void Seri1_PushSend(unsigned char mData)
*Seri1_WriteSendPoint=mD
if(Seri1_WriteSendPoint==(xBuf_Send_1+XBUFSERIAL1SEND-1)){
Seri1_WriteSendPoint=xBuf_Send_1;
else Seri1_WriteSendPoint++;
Seri1_SendNum++;
if(fSeri1_Send_Ok==0){fSeri1_Send_Ok=1;TI_1=1;}
/**************************************************
弹出串口1接收队列单数据
**************************************************/
unsigned char Seri1_PopReci()
i=*Seri1_ReadReciP
if(Seri1_ReadReciPoint==(xBuf_Reci_1+XBUFSERIAL1RECI-1))
Seri1_ReadReciPoint=xBuf_Reci_1;
else Seri1_ReadReciPoint++;
Seri1_ReciNum--;
/**************************************************
CY=0,使用T1;CY=1,使用T2
入口:Location=0,串口0;否则串口1
mBps,波特率。参考Const.h中的定义
mMode,方式。2慰糃onst.h中的定义
**************************************************/
void Init_Serial(unsigned char Location,unsigned char mBps,unsigned char mMode)
if(CY==0){ /*T1*/
TMOD=(TMOD&0x0f)|0x20; /*自动重装*/
if(Location){ /*second*/
if(ACC7)CKCON|=0x20; /*x3*/
if(ACC6)WDCON|=0x80; /*x2*/
if(ACC7)CKCON|=0x10; /*x3*/
if(ACC6)PCON|=0x80; /*x2*/
mBps&=0x3f;
TL1=TH1=(~mBps)+1;
if(ACC7)CKCON|=0x40; /*x3*/
if(ACC6==0)mBps&&=1; /*x2*/
mBps&=0x3f;
TL2= RCAP2L=(~mBps)+1;
TH2=RCAP2H=0
T2CON|=0x30; /*选择T2为波特率发生器*/
if(Location==0){
SCON|=0x40; /*方式8位*/
SCON1|=0xc0; /*方式9位*/
SCON1|=0x40; /*方式8位*/
fSeri1_Odd=ACC4; /*奇偶效验方式,0奇*/
/**************************************************
**************************************************/
void Int_serial0() interrupt 4 using 1{
// ES=0; /*关
串行口中断*/
TI = 0; /*清
发送中断标志*/
if(Seri0_SendNum==0)fSeri0_Send_Ok=0; /*已发送完毕*/
SBUF=*Seri0_ReadSendP
if(Seri0_ReadSendPoint==(xBuf_Send_0+XBUFSERIAL0SEND-1))
Seri0_ReadSendPoint=xBuf_Send_0;
else Seri0_ReadSendPoint++;
Seri0_SendNum--;
*Seri0_WriteReciPoint=SBUF;
if(Seri0_WriteReciPoint==(xBuf_Reci_0+XBUFSERIAL0RECI-1))
Seri0_WriteReciPoint=xBuf_Reci_0;
else Seri0_WriteReciPoint++;
Seri0_ReciNum++;
// ES=1; /*开
/**************************************************
**************************************************/
void Int_serial1() interrupt 7 using 1{
// ES1=0; /*关
串行口中断*/
TI_1 = 0; /*清
发送中断标志*/
if(Seri1_SendNum==0)fSeri1_Send_Ok=0; /*已发送完毕*/
if((SCON1&0xc0)==0xc0){
ACC=*Seri1_ReadSendP
if(fSeri1_Odd==0)TB8=~P; /*奇效验*/
else TB8=P;
/*偶效验*/
SBUF1=*Seri1_ReadSendP
if(Seri1_ReadSendPoint==(xBuf_Send_1+XBUFSERIAL1SEND-1))
Seri1_ReadSendPoint=xBuf_Send_1;
else Seri1_ReadSendPoint++;
Seri1_SendNum--;
// SBUF1=0
*Seri1_WriteReciPoint=SBUF1;
if(Seri1_WriteReciPoint==(xBuf_Reci_1+XBUFSERIAL1RECI-1))
Seri1_WriteReciPoint=xBuf_Reci_1;
else Seri1_WriteReciPoint++;
Seri1_ReciNum++;
/*开中断*/
/***********************************************************
串口1打包程序
***********************************************************/
void Seri1_Block()
unsigned char i,j;
if(Seri1_ReciNum==0)
if(Seri1_ReciNum&BLOCKMAX)i=BLOCKMAX;
else i=Seri1_ReciN
/*--------------------------------------*/
Seri0_PushSend(STX);
Crc8_ClrSum();
Seri0_PushSend(SERIAL1);
Crc8_AddSum(SERIAL1);
Seri0_PushSend(i);
Crc8_AddSum(i);
while(i&0){
j=Seri1_PopReci();
Seri0_PushSend(j);
Crc8_AddSum(j);
Seri0_PushSend(Crc8_GetSum());
Seri0_PushSend(ETX);
#define STX 0x02
#define ETX 0x03
#define BLOCKMAX 50
#define NONEPARITY 0x0
#define ODDPARITY 0x08
#define EVENPARITY 0x18
#define DATA7BIT 0x80
#define LOCAL 0
#define SERIAL1 1
#define SERIAL5540 2
#define SERIAL5541 3
#define SERIAL5542 4
#define SERIAL5543 5
#define SERIAL25540 6
#define SERIAL25541 7
#define SERIAL25542 8
#define SERIAL25543 9
#define RIGHT 1
#define ERROR 2
/*th=256-2^n*f/384/B*/
#define BPSM 1|0x40
#define BPS
#define BPS|0x40
#define BPS
#define BPS
#define BPS
#define BPS
#define BPS
//#define BPSM_77E58 4|0x80 /**3*/
//#define BPSE58 8|0x80 /**3*/
//#define BPSE58 2
//#define BPSE58 4
//#define BPSE58 8
//#define BPSE58 16
//#define BPSE58 32
#define XBUFSERIAL0SEND 250
#define XBUFSERIAL0RECI 2000
#define XBUFSERIAL1SEND 1800
#define XBUFSERIAL1RECI 100
#define XBUFSERIAL554RECI 186
sbit ACC0=ACC^0;
sbit ACC1=ACC^1;
sbit ACC2=ACC^2;
sbit ACC3=ACC^3;
sbit ACC4=ACC^4;
sbit ACC5=ACC^5;
sbit ACC6=ACC^6;
sbit ACC7=ACC^7;
/*初始化内部串行口,0=,1=9600*9*/
Serial0_Init
(); /*使用T2*/
CY=0;Init_Serial(1,BPS38400_22M,NONEPARITY); /*printer,使用T1*/
正好要用……谢谢
小弟最近也遇到一个串口接收数据包的的问题,通信用的是ISO14443A的通信协议
W 02& & 向下位机发送(包头)
R 10& &&&接收
W 18 41 01 00 58 10 03&&(18为一随机数,41为命令,01为数据长度且数据长度不固定,03为包尾)
R 10& &&&接收
当上位机发送02时,等待下位机响应10,如果不响应10则不发送后面的数据。各位大侠帮帮忙哈。
咋没人响应呢
我也是初学51单片机,最近想做一个串口通信工装,我主要是用串口接收对方单片机发送过来的数据用5位自带译码驱动的8421数码管显示出来,这是对方发送的一次数据01 01 01 34 35 32 36 37 32 34 31.......,由于刚学所以对把数据取出来如何让个、十、百、千、万将5个数据显示出来,刚看了很多老师的程序感到学到很多,很多是书上看不到的,先感谢各位老师的指点。
感谢LS各位高手,小弟学习了
用软件FIFO吧。
回复【17楼】728196 彳亍者
-----------------------------------------------------------------------
大段大段的代码...
这个通信程序不错
mark 。。。。
mark!!!!
再顶一下,现在做触摸屏与单片机通讯,正需要。。。。。。
这个挺有用。
接收计数i要定义成全局或静态变量,而且你这样写包头包尾没起作用,临时写一段,接收计数你测试时注意下, ...
不知道2个单片机可不可以这样做呢?
假设主机和多个从机之间就是这样通讯
主机发出一个地址码+指令码+效验
从机在中断里面根据地址码判断是不是和自己的匹配,如果是,那么判断指令码,然后返回数据给主机。
我有一个疑问,就是返回给主机的数据,是在中断里去读取呢,还是查询?
阿莫电子论坛, 原"中国电子开发网"

我要回帖

更多关于 串口寄存器 的文章

 

随机推荐