通过modbus与串口屏通讯控制

串口屏作为modbus主机,下位机主板作为从机,在从机中建立一张数据表与串口屏作为数据交换缓冲,从机移植freemodbus协议栈,定时响应串口屏的轮询

如下,在一个项目中建立的数据表

//上报给屏的槽状态
typedef struct _db_slot_status{
    uint16_t            header_cnt_before_renewing; //换油前烹饪头数
    uint16_t            header_cnt_total;           //总计头数
    uint16_t            cooking_cnt_total;          //烹饪计数
    db_time_t           recvy_time;                 //槽回温时间
    db_time_t           cooking_time;               //烹饪时间
    uint16_t            temp;                       //槽温度
    uint16_t            target_temp;                //设定目标温度
    uint16_t            cooking_mode;               //关机模式,融油模式,节能模式,预热模式,烹饪模式,滤油模式
    uint16_t            cooking_seg;                //当前段号
    uint16_t            cooking_status;             //烹饪状态,1工作或0停止
    db_time_t           total_time;                 //烹饪的总时间
    uint16_t            preheat_highlight;          //预热位,一个位对应一个菜单,置1高亮
}db_slot_status_t;

//主板上报给屏的状态
typedef union _db_status{
    uint16_t            zone[DB_STATUS_SIZE];
    struct{
        uint16_t            second;                     //主板时间秒
        uint16_t            minute;                     //主板时间分
        uint16_t            hour;                       //主板时间时
        uint16_t            day;                        //主板时间日
        uint16_t            month;                      //主板时间月
        uint16_t            year;                       //主板时间年
        uint16_t            week;                       //主板时间星期
//        uint16_t            firmware_ver;               //固件版本
//        uint16_t            hardware_ver;               //对应的硬件版本
//        uint16_t            serial_number[4];           //序列号
//        uint16_t            compile_date[12];           //编译日期
        uint16_t            cooking_cnt[DB_MENU_MAX];   //产品烹饪计数
        uint16_t            wifi_status;                //0-连接断开,1-连接WFI,2-连接服务器
        db_slot_status_t    slot_l_status;              //左槽状态
        db_slot_status_t    slot_r_status;              //右槽状态
    }data;
}db_status_t;

//自检数据
typedef union _db_selftest{
    uint16_t        zone[DB_SELFTEST_SIZE];
    struct{
        uint16_t    input1;
        uint16_t    input2;
        uint16_t    input3;
        uint16_t    input4;
        uint16_t    input5;
        uint16_t    input6;
        uint16_t    left_temp;
        uint16_t    right_temp;
        uint16_t    cpu_temp;
        uint16_t    voltage;
        uint16_t    current;
    }data;
}db_selftest_t;

typedef struct _db_para{
    
    //这两组参数是用户操作的即时控制及上报,不需保存
    db_ctrl_t           ctrl;                           //控制参数
    db_status_t         status;                         //状态参数
//    db_selftest_t       selftest;                       //自检状态
    //这两组参数需要保存到主板
    db_function_t       function;                       //功能参数
    db_cooking_menu_t   cooking_menu[DB_MENU_MAX];      //菜单参数
    
}db_para_t;

modbus初始化将modbus指针指向建立的数据表

 db_para_ptr = (db_para_t*)usSRegHoldBuf;

以下为modbus任务线程,检查数据是否有被用户修改,如被修改进行用户操作处理

void mlcd_check_variation(void)
{
    static uint8_t  crc=0,crc_new,user_update=0;
    static time_t  last_time;
    if( crc==0 ){
        //计算除去状态后的参数校验码
        crc = crc8_cal((uint8_t*)db_para_ptr+DB_START_ADDR, DB_SAVE_LEN);
    }
    
    //数据被用户通过屏幕修改
    crc_new = crc8_cal((uint8_t*)db_para_ptr+DB_START_ADDR, DB_SAVE_LEN);
    if( crc != crc_new ){
        crc = crc_new;
        last_time = time(RT_NULL);
        user_update = 1;
    }
    //用户更新10秒后保存数据
    else if( user_update ){
        if( time(RT_NULL)-last_time > 10 ){
            save_flag = 1;
            user_update = 0;
        }
    }
}

static void mlcd_task(void *parameter)
{
    eMBInit( MB_RTU, 0x01, 2, 115200, MB_PAR_NONE );
    eMBEnable();
    rt_tick_t tick =  rt_tick_get();
    while(1){
        eMBPoll();
        
        mlcd_check_variation();
        
        tick_invent = rt_tick_get()-tick;
        if( tick_invent>200 )
            tick_cnt++;
        tick =  rt_tick_get();
        
        rt_thread_delay(10);
    }
}

由于串口屏是以地址方式定位数据单元,以下两个宏用于获取数据表中相应单元的地址比较简便的方法

/** 计算结构体成员偏移地址 */  
#define offsetof(TYPE, MEMBER) ((int)(&((TYPE *)0)->MEMBER))

/** 根据成员地址获取结构首指针 */  
#define container_of(ptr, type, member) ({   \
        const typeof( ((type *)0)->member ) *__mptr = (ptr); \
        (type *)( (char *)__mptr - offsetof(type,member) );})

这种方式驱动串口屏不用关心modbus通讯,只需关注数据是否被修改,如要显示显示,将数据表相应单元的填充数据即可

你可能感兴趣的:(单片机外围电路,rt-thread,rtos,单片机,stm32,嵌入式硬件)