编程思路:
1.串口中断允许自动接收总线上的信息,当接收的 字节后超过3.5个字节时间没有新的字节认为本次
接收完成,接收完成标志置1;如果接收完成标志已 经置1又有数据进来则丢弃新来的数据。
2.串口接收数据的处理, 当接收完成标志置1进入接收数据处理, - (1)首先判断接收的第一位数据与本机地址是否相同,如果不相同清空接收缓存不发送任何信息;
- (2)接收的第一位数据与本机地址相同,则对接收缓存中的数据进行crc16校验,如果接 收的校验位与本校验结果不相同清空接收缓存不发送任何信息;
- (3)如果crc16校验正确则根据数据串中的命令码进行相应的处理。
- ******************************************************/
- #include "modbus.h"
- u8 Com0_id = 0x05;//本机串口0的通讯地址
- u8 Uart0_rev_buff[100];//com0串口接收缓冲区
- u8 Uart0_send_buff[100];//com0串口发送缓冲区
- vu8 Uart0_rev_count;
- vs8 Uart0_send_counter = 0;
- vu8 Uart0_rev_comflag;
- vu8 Crc_counter = 0;//com0校验计数器
- vu8 *Uart0_send_pointer = Uart0_send_buff;//com0串口发送指针
- vu16 Mkgz_bz = 0;//模块故障标志1:输入异常,2:过压,3:欠压,4:过温
- vu16 Out_current = 50;//输出电流
- vu16 Out_voltage = 240;//输出电压
- vu16 Mkzt_bz = 0;//模块状态标志
- vu16 OutX_current = 1000;//输出限流
- vu16 Jc_voltage = 2530;//均充电压
- vu16 Fc_voltage = 2400;//浮充电压
- vu16 user_day = 1825;//使用天数
- void Delay(vu32 nCount);
- unsigned short getCRC16(volatile unsigned char *ptr,unsigned char len) ;
- void mov_data(u8 a[100],u8 b[100],u8 c);
- void Modbus_Function_3(void);
- void Modbus_Function_6(void);
- /***************************************
- 函数名称:crc16校验
- 函数功能:crc16校验
- 函数输入:字节指针*ptr,数据长度len
- 函数返回:双字节crc
- 函数编写:孙可
- 编写日期:2008年6月9日
- 函数版本:v0.2
- ****************************************/
- unsigned short getCRC16(volatile unsigned char *ptr,unsigned char len)
- {
- unsigned char i;
- unsigned short crc = 0xFFFF;
- if(len==0)
- {
- len = 1;
- }
- while(len--)
- {
- crc ^= *ptr;
- for(i=0; i<8; i++)
- {
- if(crc&1)
- {
- crc >>= 1;
- crc ^= 0xA001;
- }
- else
- {
- crc >>= 1;
- }
- }
- ptr++;
- }
- return(crc);
- }
- /***************************************
- 块数据复制数据函数
- 功能:把数组a的c个数据复制到数组b中
- 输入:指针a,指针b,数据个数c
- 返回:无
- 编写:孙可
- 编写日期:2008年3月28日
- 版本:v0.1
- ****************************************/
- void mov_data(u8 a[100],u8 b[100],u8 c)
- {
- u8 i;
- for(i=c; i>0; i--)
- {
- a = b;
- }
- }
- ///////////////////////////////////////////////////////////////////////
- void Modbus_Function_3(void)
- {
- u16 tempdress = 0;
- u8 i = 3;
- u16 crcresult;
- tempdress = (Uart0_rev_buff[2] << 8) + Uart0_rev_buff[3];
- if((tempdress >= 0x0120) & (tempdress + Uart0_rev_buff[5] < 0x0132))
- {
- Uart0_send_buff[0] = Com0_id;
- Uart0_send_buff[1] = 0x03;
- Uart0_send_buff[2] = 2 * Uart0_rev_buff[5];
- Uart0_send_counter = 2 * Uart0_rev_buff[5] + 3;
- switch(tempdress)
- {
- case 0x0120:
- {
- Uart0_send_buff = Mkgz_bz & 0xff;
- i++;
- Uart0_send_buff = (Mkgz_bz >> 8) & 0xff;
- i++;
- }//后面不放break的目的是继续往下执行
- case 0x0122:
- {
- Uart0_send_buff = Out_voltage & 0xff;
- i++;
- Uart0_send_buff = (Out_voltage >> 8) & 0xff;
- i++;
- }
- case 0x0124:
- {
- Uart0_send_buff = Out_current & 0xff;
- i++;
- Uart0_send_buff = (Out_current >> 8) & 0xff;
- i++;
- }
- case 0x0126:
- {
- Uart0_send_buff = Mkzt_bz & 0xff;
- i++;
- Uart0_send_buff = (Mkzt_bz >> 8) & 0xff;
- i++;
- }
- case 0x0128://这个地址是备用的里面的数据没有意义
- {
- Uart0_send_buff = 0x00;
- i++;
- Uart0_send_buff = 0x00;
- i++;
- }
- case 0x012A:
- {
- Uart0_send_buff = OutX_current & 0xff;
- i++;
- Uart0_send_buff = (OutX_current >> 8) & 0xff;
- i++;
- }
- case 0x012C:
- {
- Uart0_send_buff = Jc_voltage & 0xff;
- i++;
- Uart0_send_buff = (Jc_voltage >> 8) & 0xff;
- i++;
- }
- case 0x012E:
- {
- Uart0_send_buff = Fc_voltage & 0xff;
- i++;
- Uart0_send_buff = (Fc_voltage >> 8) & 0xff;
- i++;
- }
- case 0x0130:
- {
- Uart0_send_buff = 0x00;
- i++;
- Uart0_send_buff = 0x00;
- i++;
- }
- }
- //UCSRB |= (1<
- crcresult = getCRC16(Uart0_send_buff,Uart0_send_counter);
- Uart0_send_buff[Uart0_send_counter] = crcresult & 0xff;
- Uart0_send_buff[Uart0_send_counter+1] = (crcresult >> 8) & 0xff;
- Uart0_send_counter = Uart0_send_counter+2;
- Uart0_send_pointer = Uart0_send_buff;
- USART_SendData(USART1, *Uart0_send_pointer++);
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
- }
- }
- /////////////////////////////////////////////////////////////
- void Modbus_Function_6(void)
- {
- u16 tempdress = 0;
- u8 tx_flat = 0;
- u16 crcresult;
- tempdress = (Uart0_rev_buff[2]<<8) + Uart0_rev_buff[3];
- switch(tempdress)
- {
- case 0x0126:
- {
- Mkzt_bz = (Uart0_rev_buff[4]<<8) + Uart0_rev_buff[5];
- if(user_day > 0)
- {
- tx_flat = 1;
- }
- }break;
- case 0x012A:
- {
- OutX_current = (Uart0_rev_buff[4]<<8) + Uart0_rev_buff[5];
- if(user_day > 0)
- {
- tx_flat = 1;
- }
- }break;
- case 0x012C:
- {
- Jc_voltage = (Uart0_rev_buff[4]<<8) + Uart0_rev_buff[5];
- if(user_day > 0)
- {
- tx_flat = 1;
- }
- }break;
- case 0x012E:
- {
- Fc_voltage = (Uart0_rev_buff[4]<<8) + Uart0_rev_buff[5];
- if(user_day > 0)
- {
- tx_flat = 1;
- }
- }break;
- case 0x01EE:
- {
- user_day = (Uart0_rev_buff[4]<<8) + Uart0_rev_buff[5];
- tx_flat = 1;
- //eeprom_write_word (&user_day_eep,user_day);
- }break;
- default: //命令码无效不应答
- {
- tx_flat = 0;
- }
- }
- if(tx_flat == 1)
- {
- Uart0_send_buff[0] = Com0_id;
- Uart0_send_buff[1] = 0x06;
- Uart0_send_buff[2] = Uart0_rev_buff[2];
- Uart0_send_buff[3] = Uart0_rev_buff[3];
- Uart0_send_buff[4] = Uart0_rev_buff[4];
- Uart0_send_buff[5] = Uart0_rev_buff[5];
- Uart0_send_counter = 6;
- //UCSRB |= (1<
- crcresult = getCRC16(Uart0_send_buff,Uart0_send_counter);
- Uart0_send_buff[Uart0_send_counter] = crcresult & 0xff;
- Uart0_send_buff[Uart0_send_counter+1] = (crcresult >> 8) & 0xff;
- Uart0_send_counter = Uart0_send_counter+2;
- Uart0_send_pointer = Uart0_send_buff;
- USART_SendData(USART1, *Uart0_send_pointer++);
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
- }
- }
- /////////////////////////////////////////////////////////////
- void Com0_Communication(void)
- {
- s8 i =0;
- if(Uart0_rev_comflag == 1)//接收完成标志=1处理,否则退出
- {
- if(Uart0_rev_buff[0] == Com0_id)//地址错误不应答
- {
- unsigned short crcresult;
- unsigned char temp[2];
- crcresult = getCRC16(Uart0_rev_buff,Crc_counter-2);
- temp[1] = crcresult & 0xff;
- temp[0] = (crcresult >> 8) & 0xff;
- if((Uart0_rev_buff[Crc_counter-1] == temp[0])&&(Uart0_rev_buff[Crc_counter-2] == temp[1]))//crc校验错误不应答
- {
- //SETBIT(PORTC,PC6);
- Delay(1);
- switch(Uart0_rev_buff[1])
- {
- case 0x03:
- {
- if(user_day > 0)
- {
- Modbus_Function_3();
- }
- }
- break;
- case 0x06:
- {
- Modbus_Function_6();
- }
- break;
- }
- }
- }
- Uart0_rev_comflag = 0;
- for(i = 100;i > -1;i--)
- {
- Uart0_rev_buff = 0;
- }
- }
-
- }
- /*******************************************************************************
- * Function Name : Delay
- * Description : Inserts a delay time.
- * Input : nCount: specifies the delay time length.
- * Output : None
- * Return : None
- *******************************************************************************/
- void Delay(vu32 nCount)
- {
- for(; nCount != 0; nCount--);
- }
复制代码
1
|
|
|
|
有点意思,编码再规范点就更加完美了
|
|
|
|
|
这种零零碎碎的知识,没有办法学习啊。。。
看样子楼主只是简单的了解了一些modbus基础知识,但是不够系统和全面。
其实,modbus虽然比较简单,但是如果不注意有很多坑,
特别是寄存器的位数,大小端处理,浮点数,长整数的处理等等。
目前也没有什么合适的书籍系统介绍,帮助理解的。
刚刚搜了一下,只有最近清华出版的《Modbus软件开发实战指南》不错,
应该是Modbus开发方面第一书,很系统很全面,各种代码都是开源的。
内容着重讲述如何快速入门并精通Modbus软件开发技术,
适用于初学Modbus通信协议的读者,可以看看。
京东或者淘宝搜索:Modbus软件开发实战指南
应该能看到吧。.
|
|
|
|
|