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