OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3631|回复: 22

关于STM32F1精英版读取rs485传感器的数据的一些疑问

[复制链接]

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
发表于 2019-5-30 17:04:33 | 显示全部楼层 |阅读模式
5金钱
本帖最后由 郑忠毅 于 2019-5-31 10:00 编辑

现在身边设备有:
  • STM32F1的单片机开发板
  • RS485 - modbus-16的水质PH值传感器
  • RS485转USB

主要想要完成单片机读取到传感器的数据,(传感器和单片机的相互通信)。


       仔细查看了modbus协议,我的理解是 只要单片机和传感器可以相互传输字节流,就基本完成通信。具体的数据,只要把对应的十六进制数据转换一下便可以得到;在一定程度上可能不用关心CRC16的校验码,因为读取数据的报文是固定的,CRC已经计算好了,只要写死在程序里就可以;疑问一:不知道是否理解的对?)下方图片是传感器提供的通信格式;

传感器提供的通信格式

传感器提供的通信格式

       鉴于上方的理解,我使用的是 精英版 源码 《实验24 485实验》,不知道这个实验的源码是否可以满足我的需求(疑问二:不知道这个实验源码 发送 和 接收的模块,是否可以使用),使用过程中,我将u8 rs485buf[8]的值从cnt改为{0x01,0x03,0x00,0x01,0x00,0x02,0x95,0xCB},并且发送到传感器,传感器确实返回了值,但是返回的值和我在电脑上用串口工具直接连传感器时完全不一样,返回的值类似于 ff  e0  cf  c0  e  ff  ,ff  e0  ff  e0  cf  ff 这样的和通信协议上不一样的值(疑问三:为什么会返回这样的值,我该如何处理?);有趣的是为了验证是否真的是和传感器通信,我做了以下的一些调试:
  • 断开了485的物理连接,不会有返回值;
  • 修改单片机的CRC(修改最后的2个字节,随便改为0x01,0x03,0x00,0x01,0x00,0x02,0x95,0xCC),也不会有如何设置的返回;
下图是使用串口工具连接传感器是调试的页面,可以用正常返回报文。
QQ截图20190530154918.png

从零开始搞这些,感觉非常吃力,之前一直WEB开发,非常感谢能有大佬可以帮忙解惑。

下方是实验源码
实验24 485实验.zip (3.3 MB, 下载次数: 77)

最佳答案

查看完整内容[请看2#楼]

RS485_Receive_Data这个还是函数是你写的吧 ,感觉里面很多错误 buf=RS485_RX_BUF;地址不偏移吗 其次串口2中断接收res =USART_ReceiveData(USART2);后面写上 USART_SendData(USART1,res ); 用串口1看看接收的原始数据到底是啥,记得串口1 2 波特率初始化一样
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-30 17:04:34 | 显示全部楼层
郑忠毅 发表于 2019-5-31 09:48
#include "sys.h"                    
#include "rs485.h"         
#include "delay.h"

RS485_Receive_Data这个还是函数是你写的吧 ,感觉里面很多错误
buf=RS485_RX_BUF;地址不偏移吗

其次串口2中断接收res =USART_ReceiveData(USART2);后面写上
USART_SendData(USART1,res ); 用串口1看看接收的原始数据到底是啥,记得串口1 2 波特率初始化一样
回复

使用道具 举报

10

主题

778

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6745
金钱
6745
注册时间
2017-4-12
在线时间
1258 小时
发表于 2019-5-30 17:27:36 | 显示全部楼层
CRC校验码是要计算的,不是不变的,根据命令帧计算出来的
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-30 17:39:43 | 显示全部楼层
MODBUS调试助手.rar (1.1 MB, 下载次数: 57)
回复

使用道具 举报

0

主题

45

帖子

0

精华

高级会员

Rank: 4

积分
624
金钱
624
注册时间
2018-5-24
在线时间
120 小时
发表于 2019-5-31 08:04:08 | 显示全部楼层
CRC16计算小软件

Crc16Setup.zip

2.26 MB, 下载次数: 42

回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:27:51 | 显示全部楼层
245925587 发表于 2019-5-30 17:27
CRC校验码是要计算的,不是不变的,根据命令帧计算出来的

那是不是命令帧不变,后面的CRC校验码就不会变
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-31 09:29:02 | 显示全部楼层
郑忠毅 发表于 2019-5-31 09:27
那是不是命令帧不变,后面的CRC校验码就不会变

是的。。。。
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:29:23 | 显示全部楼层
nashui_sx 发表于 2019-5-30 17:39
用专业的调试助手把
用03号命令直接读取就好了

这个工具我用过的,现在主要问题是编程过程中,读取传感器返回的值不对。
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-31 09:31:45 | 显示全部楼层
郑忠毅 发表于 2019-5-31 09:29
这个工具我用过的,现在主要问题是编程过程中,读取传感器返回的值不对。

能有啥不对,crc校验不通过的数据你又不处理,
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:37:01 | 显示全部楼层

是这样的,我现在主要问题可能是编程上,单片机读来的数据完全不对,可以帮忙看看吗?单片机返回的数据没有按照协议来,反而是 ff  e0  cf  c0  e  ff 这样的数据,但是如果命令不对,单片机又读取不了返回的数据,这个很困扰我
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:41:48 | 显示全部楼层
nashui_sx 发表于 2019-5-31 09:31
能有啥不对,crc校验不通过的数据你又不处理,

返回的数据理论上是按照modbus协议来类似于 01 03 02 00 00 BB 44 有ID地址,功能码,数据,CRC校验码之类的,但是我收到的数据是ff  e0  ff  e0  cf  ff 这样的不规则的数据,而且在程序中我故意写错命令,真的也得不到返回的值,所以不清楚该怎么搞
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-31 09:43:45 | 显示全部楼层
郑忠毅 发表于 2019-5-31 09:41
返回的数据理论上是按照modbus协议来类似于 01 03 02 00 00 BB 44 有ID地址,功能码,数据,CRC校验 ...

上代码吧,测试下就知道代码还是硬件问题了
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:47:23 | 显示全部楼层
nashui_sx 发表于 2019-5-31 09:43
上代码吧,测试下就知道代码还是硬件问题了

好的,代码就是 《实验24 485实验》的代码,基本没什么改 我马上发一下main和rs485.c
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:47:54 | 显示全部楼层
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"         
#include "rs485.h"


/************************************************
ALIENTEK精英STM32开发板实验24
485 实验
技术支持:www.openedv.com
淘宝店铺:http://eboard.taobao.com
关注微信公众平台微信号:"正点原子",免费获取STM32资料。
广州市星翼电子科技有限公司  
作者:正点原子 @ALIENTEK
************************************************/
                                        
int main(void)
{         
        u8 key;
        u8 i=0,t=0,j=0;
        u8 cnt=0;
        u8 rs485buf[8];
        u8 rs485bufA[8] = {0x01,0x03,0x00,0x01,0x00,0x02,0x95,0xCB};
       
        delay_init();                     //延时函数初始化          
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
        uart_init(115200);                 //串口初始化为115200
        LED_Init();                                  //初始化与LED连接的硬件接口
        LCD_Init();                                   //初始化LCD        
        KEY_Init();                                //按键初始化                          
        RS485_Init(9600);        //初始化RS485
        POINT_COLOR=RED;//设置字体为红色
        LCD_ShowString(30,50,200,16,16,"ELITE STM32");
        LCD_ShowString(30,70,200,16,16,"RS485 TEST");       
        LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
        LCD_ShowString(30,110,200,16,16,"2015/1/15");       
        LCD_ShowString(30,130,200,16,16,"KEY0:Send");        //显示提示信息               

        POINT_COLOR=BLUE;//设置字体为蓝色          
        LCD_ShowString(30,150,200,16,16,"Count:");                        //显示当前计数值       
        LCD_ShowString(30,170,200,16,16,"Send Data:");                //提示发送的数据       
        LCD_ShowString(30,210,200,16,16,"Receive Data:");        //提示接收到的数据               
                                                                          
        while(1)
        {
                key=KEY_Scan(0);
                if(key==KEY0_PRES)//KEY0按下,发送一次数据
                {
                        LCD_ShowxNum(130,170,cnt,2,16,0X80);
                        LCD_ShowString(30,230,200,16,16,"-----------------------");//清空 Receive Data
                        //for(i=0;i<5;i++)
                        //{
                                //rs485buf=cnt+i;//填充发送缓冲区
                                //LCD_ShowxNum(30+i*32,190,rs485buf,3,16,0X80);        //显示数据
                        //}
                       
                        for(i=0;i<8;i++)
                        {
                                rs485buf=rs485bufA;
                                LCD_ShowxNum(30+i*30,190,rs485buf,3,16,0X80);        //显示数据
                        }
                        RS485_Send_Data(rs485buf,8);//发送8个字节
                        printf("S: %d\r\n",key);       
                }                 
                RS485_Receive_Data(rs485buf,&key);
               
                //LCD_ShowString(30,230,200,16,16,"                          ");//清空 R
               
                if(key)//接收到有数据
                {
                       
                        printf("R: %d--\r\n",key);
                        if(key>8)key=8;//最大是5个数据.
                        for(i=0;i<key;i++)
                        {
                                printf(" %x ",rs485buf);
                                LCD_ShowxNum(30+i*32,230,rs485buf,3,16,0X80);        //显示数据
                        }
                        printf("\r\n--");
                }
                t++;
                delay_ms(10);
                if(t==20)
                {
                        LED0=!LED0;//提示系统正在运行       
                        t=0;
                        cnt++;
                        LCD_ShowxNum(30+48,150,cnt,3,16,0X80);        //显示数据
                }                  
        }
}


回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 09:48:32 | 显示全部楼层
#include "sys.h"                    
#include "rs485.h"         
#include "delay.h"

//////////////////////////////////////////////////////////////////////////////////         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//RS485驱动 代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/9
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved                                                                          
//////////////////////////////////////////////////////////////////////////////////


#ifdef EN_USART2_RX           //如果使能了接收


//接收缓存区        
u8 RS485_RX_BUF[64];          //接收缓冲,最大64个字节.
//接收到的数据长度
u8 RS485_RX_CNT=0;                     
  
void USART2_IRQHandler(void)
{
        u8 res;            

        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
        {         
                                  
                res =USART_ReceiveData(USART2);         //读取接收到的数据
                if(RS485_RX_CNT<64)
                {
                        RS485_RX_BUF[RS485_RX_CNT]=res;                //记录接收到的值
                        RS485_RX_CNT++;                                                //接收数据增加1
                }
        }                                                                                           
}
#endif                                                                                 
//初始化IO 串口2
//pclk1CLK1时钟频率(Mhz)
//bound:波特率          
void RS485_Init(u32 bound)
{  
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);//使能GPIOA,D时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;                                 //PD7端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOD, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;        //PA2
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

        RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE);//复位串口2
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE);//停止复位

       
#ifdef EN_USART2_RX                          //如果使能了接收
        USART_InitStructure.USART_BaudRate = bound;//波特率设置
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;///奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式

  USART_Init(USART2, &USART_InitStructure); ; //初始化串口
  
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级2级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
        NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
   
  USART_Cmd(USART2, ENABLE);                    //使能串口

#endif

  RS485_TX_EN=0;                        //默认为接收模式

}

//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void RS485_Send_Data(u8 *buf,u8 len)
{
        u8 t;
        RS485_TX_EN=1;                        //设置为发送模式
          for(t=0;t<len;t++)                //循环发送数据
        {
                printf(" %x ",buf[t]);
                while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);          
                USART_SendData(USART2,buf[t]);
        }         
  printf("\r\n--");
        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);               
        RS485_RX_CNT=0;          
        RS485_TX_EN=0;                                //设置为接收模式       
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf,u8 *len)
{
        u8 rxlen=RS485_RX_CNT;
        u8 i=0;
        *len=0;                                //默认为0
        delay_ms(10);                //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
        if(rxlen==RS485_RX_CNT&&rxlen)//接收到了数据,且接收完成了
        {
                //printf("RS485_RX_CNT: %d \r\n",RS485_RX_CNT);
                //printf("rxlen: %d \r\n",rxlen);
                for(i=0;i<rxlen;i++)
                {
                       
                        buf=RS485_RX_BUF;       
                }               
                *len=RS485_RX_CNT;        //记录本次数据长度
                RS485_RX_CNT=0;                //清零
        }
}





















回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 10:31:21 | 显示全部楼层
nashui_sx 发表于 2019-5-31 10:18
RS485_Receive_Data这个还是函数是你写的吧 ,感觉里面很多错误
buf=RS485_RX_BUF;地址不偏移吗

这里代码一点没动过, 我先按你说的试试看吧
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 11:25:54 | 显示全部楼层
nashui_sx 发表于 2019-5-31 10:18
RS485_Receive_Data这个还是函数是你写的吧 ,感觉里面很多错误
buf=RS485_RX_BUF;地址不偏移吗

太痛苦了,我什么都没做,就是复制了一下代码,有重新编译了一下,就成功了,不管怎么样还是感谢你的帮助
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 11:36:11 | 显示全部楼层
郑忠毅 发表于 2019-5-31 11:25
太痛苦了,我什么都没做,就是复制了一下代码,有重新编译了一下,就成功了,不管怎么样还是感谢你的帮助

成功了一次,然后又不行了。
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-5-31 11:37:15 | 显示全部楼层
郑忠毅 发表于 2019-5-31 11:25
太痛苦了,我什么都没做,就是复制了一下代码,有重新编译了一下,就成功了,不管怎么样还是感谢你的帮助

不过那是不太可能的事,你要么改了啥,要么接线变了
回复

使用道具 举报

1

主题

15

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-16
在线时间
7 小时
 楼主| 发表于 2019-5-31 14:06:48 | 显示全部楼层
nashui_sx 发表于 2019-5-31 11:37
不过那是不太可能的事,你要么改了啥,要么接线变了

就成功了一次,返回的值是符合协议的,现在又是ff e0 ef ff的什么了
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2019-6-1 11:00:26 | 显示全部楼层
郑忠毅 发表于 2019-5-31 14:06
就成功了一次,返回的值是符合协议的,现在又是ff e0 ef ff的什么了

应该是硬件问题,量一量电压啥的
回复

使用道具 举报

1

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
61
金钱
61
注册时间
2019-2-25
在线时间
17 小时
发表于 2019-6-21 13:17:52 | 显示全部楼层
楼主,搞定了没?  我现在碰到和你一样的情况,返回的应答命令完全乱的
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2019-8-15
在线时间
7 小时
发表于 2019-9-26 19:03:29 | 显示全部楼层
搞定了麻烦分享一下 谢谢
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 17:55

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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