找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 790|回复: 5
收起左侧

STC8单片机ADC采集modbus RTU0306源程序 完美连接MCGS触摸屏显示 无私分享

  [复制链接]
15605230262 发表于 2021-1-22 19:42 | 显示全部楼层 |阅读模式
无私开源

单片机源程序如下:
  1. //#include <reg52.h> //头文件不能双重包含否则全盘错误(此处不删除谨记)
  2. #include "modbus06.h"
  3. #include <string.h>
  4. #include <intrins.h>
  5. #include        "STC15Fxxxx.H"
  6. #include "ADC.H"
  7. #define uint8 unsigned char
  8. #define uint16 unsigned int

  9. sbit led=P1^0;//暂时测试使用

  10. sbit led2=P1^2;
  11. sbit led3=P1^3;
  12. char buf_string[8];  //定义数据包长度为15个字符
  13.         uint16 dzbl;//取06地址
  14.         uint16 xrz;//取写入寄存器地址的值

  15. /*定义成unsigned char类型可以显示足够大的数据,不然会出现错误*/
  16. uint8 receBuf[40];// 询问数据包 此处记住因为询问数据包都是8位 所以可以给数组规定元素数量
  17. uint8 sendBuf[40];// 响应数据包   相应数据包 严雨在此 规定最多连所以数据在内 最多20个元素
  18. uint16 BAUD=9600;
  19. uint16 TEMP_Alert=1000;
  20. uint16  TempRegister; //用于测试 字址址16
  21. uint8 gnmbl=7;//功能码变量
  22. uint8 localAddr = 0x01; //单片机控制板的地址
  23. uint8 sendCount;  //发送字节个数 发送函数中决定发送字节个数
  24. uint8 receCount=25;    //接收到的字节个数
  25. //uint8 sendPosi;    //发送位置
  26. void checkComm0Modbus(void);//查询uart接收的数据包内容函数
  27. uint16 getRegisterVal(uint16 addr,uint16 *tempData);//读取寄存器内容函数
  28. uint16 adc;
  29. uint16 adc_001;


  30. //串口发送函数
  31. /*void PutString(unsigned char *TXStr,unsigned char len)  //挨个字节发送需要给变量定义成char类型
  32. {               
  33.     ES=0;    //关闭串口中断
  34.      while(len--)
  35.     {                     
  36.         SBUF=*TXStr;//指针指向地址上面的值 赋 给 SBUF
  37.         while(TI==0);
  38.         TI=0;   
  39.         TXStr++;//地址+1
  40.     }
  41.     ES=1; //打开串口中断
  42. }*/                                                     
  43. //串口接收函数
  44. bit ReceiveString()   
  45. {
  46.           
  47.     char * RecStr=receBuf;//给这个地址赋一个变量名
  48.     char num=0;
  49.     unsigned char count=0;
  50. loop:
  51.                        //接收到一位数据马上存入这个地址
  52.     *RecStr=SBUF;//假设SBUF里面的值是一位一位发来,每一次都存入这个地址
  53.     RI=0;
  54.     count=0;

  55.     if(num<gnmbl)  //gnmbl数据长度变量,根据每一次接收到的数据进行变化,尝试连续接收15个字符 03=7 16=10
  56.     {
  57.         num++;
  58.         RecStr++;
  59.                      
  60.         while(!RI)
  61.         {
  62.             count++;
  63.             if(count>1592)return 0;    //接收数据等待延迟,等待时间太久会导致CPU运算闲置,太短会出现"数据包被分割",默认count=130
  64.         }       //由于stc15系列比89c52运行速度快 所以循环次数增加10倍  1300
  65.         goto loop;
  66.     }
  67.     return 1;
  68.                 }

  69. //定时器1用作波特率发生器
  70. void Init_USART()  
  71. {

  72.         PCON &= 0x3f;                //波特率不倍速,串行口工作方式由SM0、SM1决定
  73.         SCON = 0x50;                //8位数据,可变波特率,启动串行接收器
  74.         AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
  75.         AUXR &= 0xfe;                //串口1选择定时器1为波特率发生器
  76.         TMOD &= 0x0f;                //清除定时器1模式位
  77.         TMOD |= 0x20;                //设定定时器1为8位自动重装方式
  78.         TL1 = 0xDC;                  //设定定时初值
  79.         TH1 = 0xDC;                  //设定定时器重装值
  80.         ET1 = 0;                    //禁止定时器1中断
  81.         TR1 = 1;                    //启动定时器1
  82.         ES = 1;                                       // 串口1中断打开
  83.         EA = 1;  
  84.        
  85. }

  86. /* CRC 高位字节值表 */
  87. /*const*/ uint8 code auchCRCHi[] = {
  88. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0/**/,
  89. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  90. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  91. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  92. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  93. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  94. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  95. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  96. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  97. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  98. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  99. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  100. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  101. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  102. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  103. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  104. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  105. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  106. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  107. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  108. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  109. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  110. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  111. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  112. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  113. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
  114. } ;
  115. /* CRC低位字节值表*/
  116. /*const*/ uint8 code auchCRCLo[] = {
  117. 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06/**/,
  118. 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
  119. 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,                  
  120. 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
  121. 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
  122. 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  123. 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
  124. 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
  125. 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
  126. 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
  127. 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
  128. 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  129. 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
  130. 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
  131. 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
  132. 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
  133. 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
  134. 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  135. 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
  136. 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
  137. 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  138. 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
  139. 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
  140. 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  141. 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
  142. 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
  143. } ;
  144. /***************************CRC校验码生成函数 ********************************/
  145. //函数功能:生成CRC校验码
  146. //本代码中使用查表法,以提高运算速度
  147. /****************************************************************************/
  148. uint16 crc16(uint8 *puchMsg, uint16 usDataLen) //定义了recebuf首地址 和一个 5
  149. {
  150. uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
  151. uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
  152. uint16 uIndex ; /* CRC循环中的索引 */
  153. while (usDataLen--) /* 传输消息缓冲区 */
  154. { /* 计算CRC */
  155.   uIndex = uchCRCHi ^ *puchMsg++ ;//CRC 通用算法
  156.   uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; //
  157.   uchCRCLo = auchCRCLo[uIndex] ; //
  158. }
  159. return (uchCRCLo << 8 | uchCRCHi) ;
  160. }
  161. /*******************************串口发送函数 ********************************/
  162. //函数功能:将数据包通过串口发送至主机
  163. //有待修改......
  164. /****************************************************************************/
  165. //开始发送
  166. void Begin_send(void)
  167. {
  168. uint16 i=0;
  169.         ES=0;    //关闭串口中断
  170. while(sendCount--)
  171. {
  172.   SBUF = sendBuf[i++];// 响应数据包发送
  173.   while(!TI);         //发送中断标志位
  174.         TI=0;
  175. }
  176. ES=1; //打开串口中断
  177. }
  178. /********从机响应主机问询函数,function code : 03,读取多个寄存器值 ********/
  179. //函数功能:丛机根据串口接收到的数据包receBuf[]里面的内容,根据被读取寄存器
  180. //的起始地址和读取的寄存器个数,去读相应的寄存器的值,并将读取的数据以MODBUS
  181. //响应数据的标准格式打包,经过串口发送到主机。数据包格式同上。
  182. /****************************************************************************/
  183. // 询问数据包格式:
  184. //receBuf[0] receBuf[1]  receBuf[2]     receBuf[3]   receBuf[4]       receBuf[5]    receBuf[6]   receBuf[7]
  185. //询问数据格式:receBuf[]={从站地址, 功能码,  起始地址高位,起始地址低位,寄存器数高位,   寄存器数低位, 校验码低位, 校验码高位}

  186. // 响应数据包格式:
  187. // sendBuf[0] sendBuf[1]  sendBuf[[2]    sendBuf[3]  sendBuf[4]  sendBuf[5]...    receBuf[6]   receBuf[7]
  188. //响应数据格式:receBuf[]={从站地址, 功能码,    字节计数,      数据1,    数据2,     数据3,...      校验码低位, 校验码高位}

  189. void readRegisters(void)
  190. {
  191.         uint8 addr;        //起始地址复制转换变量
  192.         uint8 tempAddr;    //起始地址转换变量
  193.         uint16 crcData;    //crc 校验码生成变量
  194.         uint8 readCount;   //寄存器数复制变量
  195.         uint8 byteCount;   //数据个数变量
  196.         uint16 i;          //循环变量
  197.         uint16 tempData = 0;

  198.         //addr = (receBuf[2]<<8) + receBuf[3];
  199.         //tempAddr = addr & 0xfff;
  200.         addr = receBuf[3];                //相当于复制发送来的起始地址低位0
  201.         tempAddr = addr;//tempAddr =起始地址地位 00

  202.         //readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数
  203.         readCount = receBuf[5];          //相当于复制发送来寄存器数低位  02

  204.         byteCount = readCount * 2;//byteCount = 寄存器数 X 2    02 每个寄存器内容占高,低两个字节2

  205.         for(i=0;i<byteCount;i+=2,tempAddr++)
  206.         {
  207.                 getRegisterVal(tempAddr,&tempData);  //0 0&tempData 等于给出tempData变量的地址 读取寄存器内容函 函数功能:根据寄存器地址读取相应寄存器内容?  
  208.                 sendBuf[i+3] = tempData >> 8;        
  209.                 sendBuf[i+4] = tempData & 0xff;  
  210.         }

  211.         sendBuf[0] = localAddr;//单片机控制板的地址
  212.         sendBuf[1] = 3;  //功能码: 03
  213.         sendBuf[2] = byteCount;//2此次赋值发送数据个数
  214.         byteCount += 3;             //=5加上前面的地址,功能码,地址 共3+byteCount个字节
  215.         crcData = crc16(sendBuf,byteCount);
  216.         sendBuf[byteCount] = crcData & 0xff;   // CRC代码低位在前7
  217.         byteCount++;
  218.         sendBuf[byteCount] = crcData >> 8 ;           //高位在后8

  219.         sendCount = byteCount + 1;                        //例如byteCount=49,则sendBuf[]中实际上有49+1个元素待发
  220.         Begin_send();              //调用发送函数把计算出来的数据发送出去
  221. }//void readRegisters(void)
  222. /*************************查询uart接收的数据包内容函数 **************************/
  223. //函数功能:丛机根据串口接收到的数据包receBuf[1]里面的内容,即function code执行
  224. //相应的命令
  225. /********************************************************************************/
  226. void checkComm0Modbus(void)//查询uart接收的数据包内容函数
  227. {
  228. uint16 crcData;      //取CRC校验码变量
  229. uint16 ccc; //ccc判断CRC校验码变量
  230. //tempData,

  231. receCount=25;        //比较多余
  232. if(receCount > 4)    //接收到的字节个数
  233. {
  234.   switch(receBuf[1])
  235.   {
  236.    case 3:                      //读取保持寄存器(一个或多个)
  237.    {led=0;
  238.                  gnmbl=7;                 //功能码03循环次数固定7次,接收函数中判?
  239.                  
  240.                                   
  241.     if(receCount >= 8)          //从询问数据包格式可知,receCount应该等于8
  242.     {                           //接收完成一组数据
  243.                                 //应该关闭接收中断
  244.       
  245.       if(receBuf[0]==localAddr)                //核对地址
  246.       {led2=0;
  247.       crcData = crc16(receBuf,6);                                       //核对校验码
  248.                         ccc=receBuf[7]<<8 | receBuf[6];          //CRC校验码 是两个16进制8位二进制数
  249.       if(crcData == ccc)                       //如果校验码正确 执行读寄存器函数
  250.                         { led3=0;
  251.         if(receBuf[1] == 3)
  252.         readRegisters();                        //function code : 03?//读取保持寄存器(一个或多个)
  253.       }
  254.                        
  255.       }
  256.     }      
  257.       receCount = 0;
  258.           break;
  259.    }
  260.          case 6:
  261.          {
  262.                  gnmbl=7;

  263.       crcData = crc16(receBuf,6);                                       //核对校验码
  264.                         ccc=receBuf[7]<<8 | receBuf[6];
  265.                  if(crcData == ccc)                       //如果校验码正确 执行读寄存器函数
  266.                  {dzbl=receBuf[2]<<8 | receBuf[3];//取寄存器地址
  267.                  xrz=receBuf[4]<<8 | receBuf[5];//取写入值
  268.                  modbusRTU06(&dzbl,&xrz);}//取dzbl和xrz 的地址 并被此函数调用
  269.                  sendBuf[0] = localAddr;
  270.                  sendBuf[1] = 0x06;
  271.                  sendBuf[2] = receBuf[2];
  272.                  sendBuf[3] = receBuf[3];
  273.                  sendBuf[4] = receBuf[4];
  274.                  sendBuf[5] = receBuf[5];
  275.                  sendBuf[6] = receBuf[6];
  276.                  sendBuf[7] = receBuf[7];
  277.                  sendCount = 8;
  278.      Begin_send();
  279.                  receCount = 0;
  280.                  break;
  281.    }
  282.    

  283.   default: break;  
  284.   }
  285. }
  286. }//void checkComm0(void)



  287. /*******************************读取寄存器内容函数 **************************/
  288. //函数功能:根据寄存器地址读取相应寄存器内容
  289. /****************************************************************************/
  290. //取寄存器值 返回0表示成功
  291. uint16 getRegisterVal(uint16 addr,uint16 *tempData)
  292. {
  293. uint16 result = 0;
  294. uint8 qq=0xff;
  295. uint16 tempAddr;

  296. tempAddr = addr & 0xfff;

  297. switch(tempAddr & 0xff)
  298. {
  299. case 0x00:{ *tempData = adc; break; }//读取01开关A温度

  300. 省略
  301. 省略
  302. 省略

  303. case 0x80:{ *tempData = TempRegister; break; }//读取秒寄存器  
  304. default:  break;  
  305. }
  306. return result;
  307. }//uint16 getRegisterVal(uint16 addr,uint16 &data)

  308. /***************************
  309.         主函数
  310. ***************************/
  311. void main()
  312. {
  313.         unsigned int        TempPhoto,adc_01;       
  314.        
  315.         /*进入主函数打开串口中断,然后初始化一次,发送一组数据,然后进入空循环*/
  316.     EA=1;
  317.     Init_USART();
  318. P3M1 &= 0xFE;        P3M0 &= 0xFE;                          //设置P3.0为准双向口
  319.         P3M1 &= 0xFD;        P3M0 |= 0x02;                          //设置P3.1为推挽输出
  320.        
  321.           //ADC_config();                                 //ADC初始化  如果只调用一个AD端口可以使用初始化,避免反复开关AD寄存器
  322.         delay_ms(10);                                 //初始化后延时
  323.         //PutString("ABCDEFGHRJKLNMOPQRSTUVWXYZ\r\n",sizeof("ABCDEFGHRJKLNMOPQRSTUVWXYZ\r\n"));//测试发送函数,我的keil没破解代码量已超
  324.     while(1)
  325.     {
  326.                         TempPhoto=0;
  327.                         adc_01=0;
  328.                         delay_ms(20);
  329.                        
  330.                         //ADC_config();
  331.                         TempPhoto = Get_ADC12bitResult()*123/2004;                //实时读取P0.6通道的AD转换结果
  332.                         adc=TempPhoto;
  333.                         delay_ms(200);
  334.                        
  335.                         adc_01=adc_p01()*123/2004;
  336.                         adc_001=adc_01;
  337.             delay_ms(200);
  338.                         //空循环中如果接收到串口数据,立马进入串口中断程序
  339.         //PutString(buf_string);//空格20H,回车0DH
  340.                
  341.         
  342.     }
  343. }
  344. /************************
  345.         中断函数
  346. ************************/
  347. //串口中断服务函数-----------
  348. void USART() interrupt 4   //标志位TI和RI需要手动复位,TI和RI置位共用一个中断入口
  349. {
  350.     if(ReceiveString())   //进入串口中断首先进入串口接收函数进行判断
  351.     {
  352.         //数据包长度正确则执行以下代码
  353.         //Deal_UART_RecData();
  354.        
  355.        
  356. checkComm0Modbus();}                       
  357.    
  358.     else
  359.     {
  360.         //数据包长度错误则执行以下代码
  361.         //LED1=~LED1;               
  362.     }
  363.     RI=0;  //接收并处理一次数据后把接收中断标志清除一下,拒绝响应在中断接收忙的时候发来的请求
  364. }
复制代码
51hei.png
所有程序51hei提供下载:
stc8 ADC两路采集modbus0306从机程序20201224更新.rar (89.13 KB, 下载次数: 76)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

学生1 发表于 2021-1-27 10:55 | 显示全部楼层
能说一下屏幕上怎么设置吗?
回复

使用道具 举报

pgdw 发表于 2021-1-28 08:20 | 显示全部楼层
正需要这方面的例程,感谢楼主无私分享,。已下载,认真学习研究一下。
回复

使用道具 举报

学生1 发表于 2021-1-30 16:01 | 显示全部楼层
大神,能说一下MCGS触摸屏要怎么写程序
回复

使用道具 举报

 楼主| 15605230262 发表于 2021-1-30 19:01 | 显示全部楼层
触摸屏的资料网上大把,还有官方的。这是我研究一个月的成果,感谢大家赞赏
回复

使用道具 举报

pgdw 发表于 2021-4-7 09:36 | 显示全部楼层
感谢楼主无私开源
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表