当前位置:   article > 正文

基于STM32 RS485传感器数据采集(参考正点原子部分代码)_rs485_rx_flag

rs485_rx_flag

目前工业上,传感器一般都选RS485,modbus通讯协议,这种通讯方式,有很强的鲁棒性,本篇文章基于原子哥的精英板进行开发。

1、初始化与电脑通信的串口(PA9 PA10)

  1. //初始化USART2
  2. void RS485_Init(void)
  3. {
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. USART_InitTypeDef USART_InitStructure;
  6. NVIC_InitTypeDef NVIC_InitStructure;
  7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);
  8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
  9. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;//PA2(TX)复用推挽输出
  10. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  11. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  12. GPIO_Init(GPIOA,&GPIO_InitStructure);
  13. GPIO_SetBits(GPIOA,GPIO_Pin_2);//默认高电平
  14. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;//PA3(RX)输入上拉
  15. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //修改原GPIO_Mode_IPU(输入上拉)->GPIO_Mode_IN_FLOATING(浮空输入)/
  16. GPIO_Init(GPIOA,&GPIO_InitStructure);
  17. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;//修改PG9(RE/DE)通用推挽输出->PD7(RE/DE)通用推挽输出//
  18. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
  19. GPIO_Init(GPIOD,&GPIO_InitStructure);
  20. GPIO_ResetBits(GPIOD,GPIO_Pin_7);//默认接收状态
  21. USART_DeInit(USART2);//复位串口2
  22. USART_InitStructure.USART_BaudRate=RS485_Baudrate;
  23. USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  24. USART_InitStructure.USART_WordLength=USART_WordLength_8b;
  25. USART_InitStructure.USART_StopBits=USART_StopBits_1;
  26. USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//收发模式
  27. switch(RS485_Parity)
  28. {
  29. case 0:USART_InitStructure.USART_Parity=USART_Parity_No;break;//无校验
  30. case 1:USART_InitStructure.USART_Parity=USART_Parity_Odd;break;//奇校验
  31. case 2:USART_InitStructure.USART_Parity=USART_Parity_Even;break;//偶校验
  32. }
  33. USART_Init(USART2,&USART_InitStructure);
  34. USART_ClearITPendingBit(USART2,USART_IT_RXNE);
  35. USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//使能串口2接收中断
  36. NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
  37. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
  38. NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
  39. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  40. NVIC_Init(&NVIC_InitStructure);
  41. USART_Cmd(USART2,ENABLE);//使能串口2
  42. RS485_TX_EN=1;//模式
  43. Timer7_Init();//定时器7初始化,用于监视空闲时间
  44. //Modbus_RegMap();//Modbus寄存器映射
  45. }

2、采用串口中断将数据保存到数组buff中

  1. void RS485_SendData(u8 *buff,u8 len)
  2. {
  3. RS485_TX_EN=1;//切换为发送模式
  4. while(len--)
  5. {
  6. while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);//等待发送区为空
  7. USART_SendData(USART2,*(buff++));
  8. }
  9. while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);//等待发送完成
  10. TX_RX_SET=1; //发送命令完成,定时器T4处理接收到的数据
  11. RS485_TX_EN=0;
  12. }

3、用定时器来配置一帧字节是否结束(空闲时间>指定时间)

  1. void TIM7_IRQHandler(void)
  2. {                                                                   
  3.     if(TIM_GetITStatus(TIM7,TIM_IT_Update)!=RESET)
  4.     {
  5.         TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除中断标志
  6.         TIM_Cmd(TIM7,DISABLE);//停止定时器
  7.         RS485_TX_EN=1;//默认为发送模式       485模式控制.0,接收;1,发送.
  8.         RS485_RxFlag=1;//置位帧结束标记
  9. //        errpace=1;
  10.     }
  11. }
  12. 4、主机发送请求指令(从机地址、功能码 、起始地址、读取个数)
  13. void modbus_rtu(void)
  14. {    
  15.     static u8 i=0;
  16.     static u8 j=0;
  17.     switch(i)
  18.     {
  19.         case 0:      //modbus执行命令第一步。
  20.                 //RS485_TX_Service();  //向从机发送一个请求。就在此时发送完成TX_RX_SET=1 发送命令完成,定时器T4处理接收到的数据
  21.             //在此处也可以直接写Master_Service( SlaverAddr, Fuction, StartAddr, ValueOrLenth);
  22.             //多次通讯结果可以按照类似的封装进行填写
  23.             
  24.             RS485_TX_Service();
  25.                if(TX_RX_SET) i=1; //发送,接受命令切换。 0 发送模式 1 接受模式
  26.             
  27.         
  28.             state=1;
  29.                 break;
  30.         case 1:     //modbus命令执行第二步。
  31.                 RS485_RX_Service();  //执行数据接收 
  32.             state=2;
  33.                 if(ComErr==0)  //如果什么错误都没有发生
  34.                 {
  35.                     i=2;//完成命令更换功能码!
  36.                 } //一次通讯已经完成
  37.                 else   //错误接收后再次准备接收
  38.                 {
  39.                     i=1;//
  40.                     j++;//一个命令发送3次没有应答切换下一个命令
  41.                     if(j>=2)
  42.                     {
  43.                         j=0;
  44.                         i=2;
  45.                         ComErr=7;  //通讯超时
  46.                     }                
  47.                 }
  48.                 break;
  49.         case 2: //从机地址++    
  50.             i=0;
  51.             state=3;
  52.                 break;
  53.         case 3://功能码,这个是空余出来做报错以及其他处理的
  54.                 break;                
  55.             
  56.     }
  57.     
  58. }

5、从机响应,通过校验码判断数据是否成功

  1. u16 CRC_Compute(u8 *puchMsg, u16 usDataLen)
  2. {
  3. u8 uchCRCHi = 0xFF ;
  4. u8 uchCRCLo = 0xFF ;
  5. u32 uIndex ;
  6. while (usDataLen--)
  7. {
  8. uIndex = uchCRCHi ^ *puchMsg++ ;
  9. uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
  10. uchCRCLo = auchCRCLo[uIndex] ;
  11. }
  12. return ((uchCRCHi<< 8) | (uchCRCLo)) ;
  13. }//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)

6、处理主机采集到的数据

  1. void USART2_IRQHandler(void)//串口2中断服务程序
  2. {
  3.        
  4.         u8 res;
  5.         u8 err;
  6.      
  7.         if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
  8.         {
  9.                 if(USART_GetFlagStatus(USART2,USART_FLAG_NE|USART_FLAG_FE|USART_FLAG_PE)) {err=1;errpace=2;}//检测到噪音、帧错误或校验错误
  10.                 else err=0;
  11.                 res=USART_ReceiveData(USART2); //读接收到的字节,同时相关标志自动清除
  12.                 
  13.                 if((RS485_RX_CNT<2047)&&(err==0))
  14.                 {
  15.                         RS485_RX_BUFF[RS485_RX_CNT]=res;
  16.                         RS485_RX_CNT++;
  17.                         
  18.                         TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除定时器溢出中断
  19.                         TIM_SetCounter(TIM7,0);//当接收到一个新的字节,将定时器7复位为0,重新计时(相当于喂狗)
  20.                         TIM_Cmd(TIM7,ENABLE);//开始计时
  21.                 }
  22.         }
  23. }
  24. void Modbus_03_Solve(void)
  25. {
  26.     u8 i;
  27.         //u8 RegNum;
  28.         //RegNum= RS485_RX_BUFF[2]/2;//获取字节数 6---->?
  29.         if(1)//寄存器地址+数量在范围内
  30.         {
  31.                 for(i=0;i<20;i++)
  32.                 {
  33.                        Master_ReadReg[StartAddr+i]= RS485_RX_BUFF[3+i*2];           /8
  34.                        Master_ReadReg[StartAddr+i]= RS485_RX_BUFF[4+i*2]+(Master_ReadReg[StartAddr+i]<<8);//8+8
  35.                                          Master_ReadReg[i]= RS485_RX_BUFF[3+i*2]; 
  36.                                          Master_ReadReg[i]= RS485_RX_BUFF[4+i*2]+(Master_ReadReg[i]<<8);//8+8
  37.                     
  38.  
  39.                 }
  40.             temp=Master_ReadReg[0];
  41.          x_shock=Master_ReadReg[1];
  42.         y_shock=Master_ReadReg[2];
  43.         z_shock=Master_ReadReg[3];                                             
  44.              //volback(message);
  45.                  ComErr=0;
  46.         }
  47.         else
  48.         {
  49.             
  50.                 ComErr=3;
  51.         }
  52.         TX_RX_SET=0; //命令完成
  53. }
  54. //Modbus功能码05处理程序   ///程序已验证OK
  55. //写单个输出开关量
  56. void Modbus_05_Solve(void)
  57. {
  58.        u16 i;
  59.        i=ValueOrLenth;
  60.        if((i>0&&RS485_RX_BUFF[4]==0XFF&&RS485_RX_BUFF[5]==0X00)||(i==0&&RS485_RX_BUFF[4]==0X00&&RS485_RX_BUFF[5]==0X00))
  61.        {
  62.             ComErr=0;
  63.             
  64.        }
  65.        else
  66.        {
  67.             ComErr=5;
  68.        }
  69.        TX_RX_SET=0; //命令完成       
  70. }
  71. //Modbus功能码06处理程序   //已验证程序OK
  72. //写单个保持寄存器
  73. void Modbus_06_Solve(void)
  74. {
  75.         u16 i; //数据返回校验用    
  76.         i=(((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//获取寄存器数量
  77.         if(i==Master_WriteReg[StartAddr])
  78.         {
  79.             ComErr=0;
  80.         }
  81.         else
  82.         {
  83.             ComErr=6;
  84.         }
  85.         TX_RX_SET=0; //命令完成
  86. }
  87. //Modbus功能码15处理程序   //程序已验证OK
  88. //写多个输出开关量
  89. void Modbus_15_Solve(void)
  90. {
  91.         u16 i;//数据返回校验用
  92.         i=(((u16)RS485_RX_BUFF[4])<<8)|RS485_RX_BUFF[5];//获取寄存器数量
  93.          if(i==ValueOrLenth)
  94.         {
  95.             ComErr=0;
  96.         }
  97.          else
  98.         {
  99.             ComErr=15;
  100.         }
  101.         TX_RX_SET=0; //命令完成   
  102. }
  103. //返回温度值
  104. u16 temperature(void)
  105. {
  106.     return temp;
  107. }
  108.  //返回x 振动
  109. u16 X_shock(void)
  110. {
  111.     return x_shock;
  112. }
  113.     
  114. //返回y 振动
  115. u16 Y_shock(void)
  116. {
  117.     return y_shock;
  118. }
  119. //返回z 振动
  120. u16 Z_shock(void)
  121. {
  122.     return z_shock;
  123. }

7、结果展示

有什么疑问或想要完整程序可私聊我 ,平时回消息都比较快

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/142480
推荐阅读
相关标签
  

闽ICP备14008679号