前言
CCS的各种第一代,第二代,第三代芯片的问世,从封装及外设功能上不断优化,缩小了成本但是提高了芯片性能。虽然国产的芯片目前无法与它媲美,但是作为嵌入式的出入门径的小新,先用好漂亮国的片子,再有机会给国产片做贡献吧(好像在痴人说梦),总之希望国产片能越来越好,实现弯道超车,从而彻底摆脱外国芯片卡脖子。
本文主要讲解本人对280025C芯片的SCI的理解,MODBUS-RTU的理解,如有错误之处敬请各位博友私信指正。
一、SCI串口通信介绍
串口通信即SCI就是平时所说的UART,是一个双线异步串行端口。SCI模块支持CPU和其他适应标准不归零格式的异步外围设备间的数字通信。SCI的接收器和发送器各自拥有一个16级深度的FIFO,可独立运行在半双工或者联合运行在全双工通信。
二、SCI通讯格式
SCI异步通信格式既可以使用单线通信,也可以使用双线通信。在此模式中,帧由1位起始位、1~8位数据位,1位可选择的奇偶校验位和1~2位停止位构成。每个数据位占8个SCICLK时钟周期。接收器在收到有效的起始位后开始工作,一个有效的起始位由四个连续的内部SCICLK周期的低电平来确定。如果没有连续的低电平,处理器就会重新启动便于开始寻找新的起始位。(有个问题:在多个处理器通信时是否需要判断总线的状态是否忙碌,这个问题一直困扰我)
三、MODBUS通信规约
MODBUS通信是一种广泛应用于电子控制器之间的一种通用语言,通过此协议,控制器之间相互可以通信。此协议定义了一个控制器能够认识使用的消息结构,可分为两种数据传输模式,ASCII与RTU模式。大体分为地址域,功能域,数据域,CRC校验域。在此不再赘述详细MODBUS协议内容,可自行上网查询。
四、基于SCI的MODBUS协议的经典应用
经过学习与总结,利用队列探索了一套常用的,不丢帧的通信程序(自己称作三指针法),大体流程如下:
1)、消息接受
1、新建三个指针Uint16 *pbBufHead; Uint16 *pbBufDeal; Uint16 *pbRptr;与一个接受消息的队列(他们都叫Buffer,但是我不习惯这么中英混着叫,有点装逼的感觉)。
2、初始化指针都指向队列的头
UartHost.pbBufHead = UartHost.ReceBuf; //指针初始化
UartHost.pbBufTail = UartHost.ReceBuf; //指针初始化
UartHost.pbBufDeal = UartHost.ReceBuf; //指针初始化
UartHost.pbRptr = UartHost.ReceBuf; //指针初始化
3、根据MODBUS协议判断接收消息的每个字节,由于一个完整的数据帧都是由地址域+功能域+数据域+校验域构成,所以需要判断出4个字节的信息是否满足MODBUS协议。当接受到一个消息时,数据被存放在队列ReceBuf中,UartHost.pbBufDeal++是关键,只有判断接受帧的地址位正确,才会判断下一个字节,否则该字节被直接抛弃。
//以查询方式接收
if(ScicRegs.SCIRXST.bit.RXRDY == 1)
{
*UartHost.pbRptr++ = ScicRegs.SCIRXBUF.all; // Read data
if (UartHost.pbRptr >= (UartHost.ReceBuf + MAX_RECE_BUF_LEN))
UartHost.pbRptr = UartHost.ReceBuf;
}
此时判断如果UartHost.pbBufDeal!=*UartHost.pbRptr则说明有数据放入消息队列,开始一个字节一个字节的判断,
void Class_HostModbusComm::fnHostFrameJudge()
{
'''
while(UartHost.pbBufDeal!= UartHost.pbRptr)
{
switch(UartHost.ReceSta)
{
case 0:
if(*UartHost.pbBufDeal ==objDigitalIO.m_st_wLocalSignal2.bModuleID)//需要加地址
{
UartHost.pbBufHead = UartHost.pbBufDeal;
fram_len = 0;
UPS_ID_NUM=objDigitalIO.m_st_wLocalSignal2.bModuleID;
tmpbuf[fram_len++] = *UartHost.pbBufDeal;
UartHost.ReceSta++;
}
break;
...//省略
default:
fnHostErrCode();
fram_len = 0;
UartHost.ReceSta = 0;
break;
}
UartHost.pbBufDeal++;
if( UartHost.pbBufDeal >= (UartHost.ReceBuf + MAX_RECE_BUF_LEN) )
{UartHost.pbBufDeal = UartHost.ReceBuf;}
}
2)、接受消息处理
首先判断地址,功能码,最后判断CRC校验码,当收到一个完整的帧后,开始执行此步骤,否则将不会进入消息的发送。
3)、消息发送
一样采用指针++的方法进行消息发送,根据接收到的命令选择不同的消息发送命令,发送一个字符(完整的串口帧1位起始位+8位数据位+1位奇偶校验位+1位停止位)后指针++.
总结
以上只是对串口通信及MODBUS的简单介绍,但是经过一个星期的磨练,已经成功将上述的消息处理的方法应用于产品,消息通信校通率完全满足工业要求,不会存在漏帧、误判的情况。值得各位同仁与博友借鉴,如果想要完整代码可与我联系,我将很高兴与大家共享。