OpenEdv-开源电子网

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

分享模拟串口RS485代码【YS8156B氨气传感器等】MODBUS 协议(RTU 方式)

[复制链接]

4

主题

9

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-4-22
在线时间
6 小时
发表于 2016-4-22 16:29:23 | 显示全部楼层 |阅读模式
本帖最后由 lengjingzju 于 2016-4-22 17:10 编辑



适用于某些工业级O2/CO2/NH3等测量传感器


///////////////
////crc16.c////
///////////////


//CRC16校验


    const unsigned char auchCRCHi[] = {
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
    } ;


    const unsigned char auchCRCLo[] = {
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
        0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
        0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
        0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
        0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
        0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
        0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
        0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
        0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
        0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
        0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
        0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
        0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
        0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
        0x43, 0x83, 0x41, 0x81, 0x80, 0x40
    } ;




unsigned short crc16(unsigned char *puchMsg, unsigned short usDataLen){
    unsigned char uchCRCHi = 0xFF ;
    unsigned char uchCRCLo = 0xFF ;
    unsigned int uIndex ;


    while (usDataLen--){
         uIndex = uchCRCHi ^ *puchMsg++ ;
         uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
         uchCRCLo = auchCRCLo[uIndex] ;
    }
    return (uchCRCHi << 8 | uchCRCLo) ;
}

///////////////////
////CO2_RS485.h////
///////////////////

#ifndef __CO2_RS485_H
#define __CO2_RS485_H

#include "stm32f4xx_conf.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"

//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"  //ucos 使用
#endif

#define CO2_RS485_RX         PAin(3)
#define CO2_RS485_TX         PAout(2)
#define CO2_RS485_TX_EN      PGout(8)    //485模式控制.0,接收;1,发送.
#define BOUND_TIME_DIV2  52  //9600波特率延时为104us,可能需要修改,因为时钟选取的HSE的频率可能有偏移

extern u8 CO2_RS485_RX_BUF[7];      //接收缓冲,7个字节
extern u8 CO2_RS485_RX_LEN;       //接收到的数据长度

void CO2_RS485_init(void);
void CO2_RS485_sendInstruction(void);
void CO2_RS485_getOneByte(void);
u16  CO2_RS485_getValue(void);//实际值单位ppm(百万分之一)
unsigned short crc16(unsigned char *puchMsg, unsigned short usDataLen);

#endif


///////////////////
////CO2_RS485.c////
///////////////////

#include "CO2_RS485.h"
u8 CO2_RS485_RX_BUF[7];      //接收缓冲,7个字节
u8 CO2_RS485_RX_LEN=0;       //接收到的数据长度


void CO2_RS485_init(void){
    GPIO_InitTypeDef   GPIO_InitStructure;
    EXTI_InitTypeDef   EXTI_InitStructure;
    NVIC_InitTypeDef   NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |RCC_AHB1Periph_GPIOG,ENABLE);//使能GPIOK时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

    //GPIO初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;      //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  //100MHz
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;       //上拉
    GPIO_Init(GPIOG, &GPIO_InitStructure);              //初始化

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_Init(GPIOA, &GPIO_InitStructure);              //初始化

    //CO2_RS485_TX_EN=0;//设置为接收模式

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

    //配置 GPIO 与中断线的映射关系
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);//PK3 连接到中断线3

    //配置EXTI_Line3
    EXTI_InitStructure.EXTI_Line = EXTI_Line3;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
    EXTI_Init(&EXTI_InitStructure);//配置

    //配置中断分组( NVIC),并使能中断
    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断3
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);//配置

}


//已在头文件定义
//#define CO2_RS485_RX         PKin(3)
//#define BOUND_TIME_DIV2  52  //9600波特率延时为104us
//u8 CO2_RS485_RX_BUF[7];      //接收缓冲,7个字节
//u8 CO2_RS485_RX_LEN=0;       //接收到的数据长度
//外部中断3服务程序
//符合标准MODBUS 协议(RTU 方式),通讯波特率固定为9600,1个起始位,8个数据位,无效验位,1个停止位。//


void EXTI3_IRQHandler(void){

#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    OSIntEnter();
#endif
    NVIC_DisableIRQ(EXTI3_IRQn);//中断除能

     CO2_RS485_getOneByte();

    NVIC_EnableIRQ(EXTI3_IRQn);//中断使能
     EXTI_ClearITPendingBit(EXTI_Line3);//清除LINE3上的中断标志位

#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    OSIntExit();
#endif
}

//已在头文件定义
//#define CO2_RS485_RX         PKin(3)
//#define CO2_RS485_TX         PKout(4)
//#define CO2_RS485_TX_EN      PKout(5)    //485模式控制.0,接收;1,发送.



void CO2_RS485_getOneByte(void){
    u8 i;
    delay_us(BOUND_TIME_DIV2);delay_us(BOUND_TIME_DIV2);
    //8个数据位,低位在前

    for(i=0;i<8;i++){
        delay_us(BOUND_TIME_DIV2);
        CO2_RS485_RX_BUF[CO2_RS485_RX_LEN] = (CO2_RS485_RX_BUF[CO2_RS485_RX_LEN] & (u8)(~(1<<i))) | (u8)CO2_RS485_RX<<i;
        //if(CO2_RS485_RX) buf=1;
        //else buf=0;
        delay_us(BOUND_TIME_DIV2);
    }
    //无奇偶校验位
    //1个停止位
    delay_us(BOUND_TIME_DIV2);delay_us(BOUND_TIME_DIV2);
    CO2_RS485_RX_LEN++;
}

void CO2_RS485_sendInstruction(void){

0422——F407_Test.zip

664.39 KB, 下载次数: 1021

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

9

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-4-22
在线时间
6 小时
 楼主| 发表于 2016-4-22 16:37:18 | 显示全部楼层
//太长被截了一段,继续

void CO2_RS485_sendInstruction(void){
        volatile u8 i;
    u8 j;
    //u8 CO2_RS485_SX_BUF[8]={0x01,0x03,0x00,0x00,0x00,0x01,0x84,0x0a};//CO2命令
    u8 CO2_RS485_SX_BUF[8]={0x01,0x03,0x00,0x14,0x00,0x01,0xc4,0x0e};//O2和NH3命令

    CO2_RS485_TX_EN=1;//设置为发送模式

    for(j=0;j<8;j++){
        //1个起始位
        CO2_RS485_TX=0;
        delay_us(BOUND_TIME_DIV2);delay_us(BOUND_TIME_DIV2);
        //8个数据位,低位在前
        for(i=0;i<8;i++){
                CO2_RS485_TX = CO2_RS485_SX_BUF[j]<<(7-i)>>7;//i & 0x01;
            //printf("CO2_RS485_TX[%x] [%x] ",i,CO2_RS485_TX);
            delay_us(BOUND_TIME_DIV2);
            delay_us(BOUND_TIME_DIV2);
        }
        //printf("SX_BUF\r\n");
        //无奇偶校验位
        //1个停止位
        CO2_RS485_TX=1;
        delay_us(BOUND_TIME_DIV2);delay_us(BOUND_TIME_DIV2);
        //printf("[%x] ",CO2_RS485_SX_BUF[j]);
    }
    //printf("SX_BUF\r\n");
    CO2_RS485_RX_LEN=0;//清空接收状态标记(长度)
    CO2_RS485_TX_EN=0;//设置为接收模式
}

u16 CO2_RS485_getValue(void){

    u8 i;
    u16 date;
    u16 receiveCrc;
    CO2_RS485_sendInstruction();
   
    delay_ms(10);

    for(i=0;i<7;i++) printf("[%x] ",CO2_RS485_RX_BUF[i]);
    printf("RX_BUF\r\n");


    receiveCrc=crc16(CO2_RS485_RX_BUF,5);

//    printf("receiveCrc is[%x] \r\n",receiveCrc);
//    printf("receiveCrc5 is[%x] \r\n",(u8)(receiveCrc>>8));
//    printf("receiveCrc6 is[%x] \r\n",(u8)(receiveCrc<<8>>8));
    if(CO2_RS485_RX_BUF[5]==(u8)(receiveCrc>>8) && CO2_RS485_RX_BUF[6]==(u8)(receiveCrc<<8>>8)){
        date=((u16)CO2_RS485_RX_BUF[3]<<8)+CO2_RS485_RX_BUF[4]; //按实际修改

        printf("CO2 value is %d. \r\n",date);
        return date;
    }
    else
        return 0; //错误返回一个0值
}
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
23
金钱
23
注册时间
2019-3-28
在线时间
8 小时
发表于 2019-4-1 12:05:12 | 显示全部楼层
请问大哥能不能将对应的传感器使用手册发一下,这样我们这些新手还能对照看一下
回复 支持 反对

使用道具 举报

7

主题

105

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1027
金钱
1027
注册时间
2016-1-28
在线时间
135 小时
发表于 2019-4-11 10:36:25 | 显示全部楼层
谢谢楼主分享,很有作用。
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1223
金钱
1223
注册时间
2019-5-30
在线时间
95 小时
发表于 2019-5-30 16:49:48 | 显示全部楼层
要是L4系列该多好
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-15 00:22

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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