|
從大學畢業到現在,重新學習了下51單片機,最近站在各位前輩大佬的肩膀上,調試了一下STC15W408AS的一個MODBUS_RTU的通訊,程序能夠調通,但是用modscan32的時候,只能讀連續的18個數值,搞不懂了。貼上代碼,請各位大神幫忙看看
4002是程序做的自加不用管,其他初始化為0
連續18個數值.png (76.51 KB, 下載次數: 48)
下載附件
2020-6-19 16:06 上傳
4002是程序做的自加不用管,其他初始化為0
連續19 個數值.png (81.03 KB, 下載次數: 37)
下載附件
2020-6-19 16:06 上傳
****本行不是代碼*****只是說明 ****** 以下是modbusRTU.c *************************************************************
單片機源程序如下:
- #include "config.h"
- #include "modbusRTU.h"
- #include "CRC16.h"
- bit flagFrame = 0; /*幀接收完成標志*/
- bit flagTxd = 0; /*單字節發送完成標志*/
- unsigned char cntRxd = 0; /*接收字節計數器*/
- unsigned char bufRxd[128]; /*接收字節緩沖區*/
- /*預定義一個或多個實參數組,用于存放需要處理的數據*/
- unsigned int idata regGroup[60]={0}; //數據緩存區,全局變量,
- unsigned int idata modbusData[2]={0}; //該數組用來存放modbus數據,分別為波特率和地址
- /*串口配置函數,baud-波特率*/
- void UartInit(unsigned int baud) //9600bps@22.1184MHz 16位自動重裝載
- {
- RS485_DIR = 0;
- SCON = 0x50; //8位數據,可變波特率
- AUXR |= 0x01; //串口1選擇定時器2為波特率發生器
- AUXR |= 0x04; //定時器2時鐘為Fosc,即1T
- T2L = (65536-SYSclk/baud/4) & 0xff; //設定定時初值,取低8位
- T2H = (65536-SYSclk/baud/4) >> 8; //設定定時初值,取高8位
- AUXR |= 0x10; //啟動定時器2
- AUXR1 = 0x40; //將串口切換到P36P37,此處之所以要將串口切換,是因為P30/P31需要作為下載口
- ES = 1;
- }
- /*串口數據寫入,即串口發送函數,buf-待發送數據指針,len-指定的發送長度*/
- void UartWrite(unsigned char *buf, unsigned char len)
- {
- RS485_DIR = 1;
- while(len--)
- {
- flagTxd = 0; //清零發送標志
- SBUF = *buf++; //發送一個字節數據
- while(!flagTxd);
- }
- // DelayX10us(5);
- Delay5ms(); //延時5ms,等待一幀數據的最后3.5字符發送完成
- RS485_DIR = 0;
- }
- /*串口數據讀取,buf-接收數據指針,len-指定的讀取長度,返回值,實際讀到的數據長度*/
- unsigned char UartRead(unsigned char *buf, unsigned char len)
- {
- unsigned char i;
- if(len > cntRxd) //指定讀取長度 大于 實際接收到的長度時,
- { //讀取長度設置為實際接收到的數據長度
- len = cntRxd;
- }
- for(i=0;i<len;i++)
- {
- *buf++ = bufRxd[i];
- }
- cntRxd = 0;
- return len;
- }
- /*串口接收監控,由空閑時間判定幀結束,需在定時中斷中調用,ms-定時間隔*/
- void UartRxMonitor(unsigned char ms)
- {
- static unsigned char cntbkp = 0;
- static unsigned char idlemr = 0;
- if(cntRxd >0)
- {
- if(cntbkp != cntRxd)
- {
- cntbkp = cntRxd;
- idlemr = 0;
- }
- else
- {
- if(idlemr < 50)
- {
- idlemr = idlemr + ms;
- }
- if(idlemr >= 50)
- {
- flagFrame = 1;
- }
- }
- }
- else
- {
- cntbkp = 0;
- }
- }
- /*串口驅動函數,監測數據幀的接收,調用函數功能,需要在主函數中調用*/
- void UartDriver()
- {
- unsigned char len;
- unsigned char xdata buf[40];
- if(flagFrame)
- {
- flagFrame = 0;
- len = UartRead(buf,sizeof(buf)-2);
- UartAction(buf,len);
- }
- }
- void InterruptUART() interrupt 4
- {
- if(RI)
- {
- RI = 0;
- if(cntRxd < sizeof(bufRxd))
- {
- bufRxd[cntRxd++] = SBUF;
- }
-
- }
- if(TI)
- {
- TI = 0;
- flagTxd = 1;
- }
- }
- /*串口動作函數,根據接收到的信號執行相應的動作
- buf-接收到的命令幀指針,len - 命令幀長度*/
- void UartAction(unsigned char *buf, unsigned char len)
- {
- unsigned int crc;
- unsigned char crcl,crch;
- unsigned char i = 0;
- unsigned char cnt = 0;
-
- if(buf[0] != modbusData[1])
- {
- return;
- }
- crc = GetCRC16(buf,len-2); //計算CRC
- crcl = crc & 0xff; //取低8位 CA
- crch = crc >> 8; //取高8位 D5 舉例 01 03 00 01 00 01 D5 CA
- if((buf[len-2] != crch) || (buf[len-1] != crcl)) //CRC校驗不通過,則退出該函數
- {
- return;
- }
- switch(buf[1])
- {
- case 0x03:
- if ((buf[2]==0x00) && (buf[3]<=0x3c))
- {
- i = buf[3]; //提取寄存器地址
- cnt = buf[5]; //提取寄存器數量
- buf[2] = cnt*2; //提取數據的字節數,為寄存器數量 *2
- len = 3; // 幀前部已經有地址、功能、字節數,所以len 從3開始算
- while(cnt--) //cnt=2
- {
- buf[len] = regGroup[i] >> 8; //高字節 len=3
- buf[len+1] = regGroup[i] & 0xff; //低字節 len = 3+1
- len = len + 2;
- i = i + 1;
- }
- break;
- }
- else //寄存器地址不被支持時,返回錯誤碼
- {
- buf[1] = 0x83; // 此處錯誤碼 為 0x03(功能碼) + 0x80(功能碼出錯時)
- buf[2] = 0x02;
- len = 3;
- break;
- }
- case 0x06:
- if((buf[2]==0x00) && (buf[3]<=0x3c))
- {
- i = buf[3]; //需要寫入的寄存器 的 地址低位
- regGroup[i] = 256 * buf[4] + buf[5];
- len = 6;
- break;
- }
- else
- {
- buf[1] = 0x86; // 此處錯誤碼 為 0x06(功能碼) + 0x80(功能碼出錯時)
- buf[2] = 0x02;
- len = 3;
- break;
- }
- default:
- buf[1] = 0x80;
- buf[2] = 0x01;
- len = 3;
- break;
- }
- crc = GetCRC16(buf,len); //計算返回幀的CRC校驗值
- buf[len] = crc >> 8; //高字節
- buf[len+1] = crc & 0xFF; //低字節
- UartWrite(buf, len+2);
- }
- ****本行不是代碼*****只是說明 ****** 以下是main.c *************************************************************
- #include "config.h"
- #include "power_led.h" /*開發板專有,啟動STC的電源和LED*/
- #include "modbusRTU.h"
- void Timer0Init(void);
- void main()
- {
- modbusData[0]=9600; //此處暫時先用常數,后期從EEPROM中讀取
- modbusData[1]=2; //此處暫時先用常數,后期從EEPROM中讀取
- STP_power();
- EA = 1;
- UartInit(modbusData[0]);
- Timer0Init();
- while(1)
- {
- UartDriver();
- }
- }
- void Timer0Init(void) //1毫秒@22.1184MHz
- {
- AUXR |= 0x80; //定時器時鐘1T模式
- TMOD &= 0xF0; //設置定時器模式
- TL0 = 0x9A; //設置定時初值
- TH0 = 0xA9; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- ET0 = 1;
- }
- /*T0中斷函數,執行串口接收監控和蜂鳴器驅動*/
- void InterruptTimer0() interrupt 1
- {
- UartRxMonitor(1);
- regGroup[1] ++;
- if(regGroup[1]>65535)regGroup[1]=0;
- }
復制代碼 |
|