STM32使用大彩屏程序总结(二)

本文介绍了如何在STM32上通过串口中断实现数据接收并将其入队,然后在主程序中处理这些指令。利用队列缓存区存储接收到的字节,通过queue_find_cmd函数拼接完整指令,并根据结构体解析指令内容。同时,文章展示了CRC16校验的实现,确保数据传输的准确性。在接收到特定指令时,执行软重置操作。
摘要由CSDN通过智能技术生成

关于串口接收入队操作,是在串口中断中实现。

void USART2_IRQHandler(void)
{   
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        uint8_t data = USART_ReceiveData(USART2);
        queue_push(data);
    }
}


/*! 
* \brief  添加指令数据
* \detial 串口接收的数据,通过此函数放入指令队列 
*  \param  _data 指令数据
*/
void queue_push(qdata _data)//1个字节
{
    qsize pos = (que._head+1)%QUEUE_MAX_SIZE;//qsize--2个字节
    if(pos!=que._tail)                                                //非满状态
    {
        que._data[que._head] = _data;
        que._head = pos;
    }
}

为了适应我的开发板,我将串口二中断打开进行入队操作。

串口通过中断每次接收一个字节的数据,并将数据放入队列缓存区

再通过主程序中的死循环中不断取数据,拼接指令

    while(1)                                                                        
    {   
        size = queue_find_cmd(cmd_buffer,CMD_MAX_SIZE);                              //从缓冲区中获取一条指令         
        if(size>0&&cmd_buffer[1]!=0x07)                                              //接收到指令 ,及判断是否为开机提示
        {                                                                           
            ProcessMessage((PCTRL_MSG)cmd_buffer, size);                             //指令处理  
        }                                                                           
        else if(size>0&&cmd_buffer[1]==0x07)                                         //如果为指令0x07就软重置STM32  
        {                                                                           
            __disable_fault_irq();                                                   
            NVIC_SystemReset();                                                                                                                                          
        }                       

注意:cmd_buffer代表一条完整的指令,通过queue_find_cmd函数取出指令,当有指令数据且非开机指令的时候,送入ProcessMessage函数进行指令处理

这里有个cmd_buffer强转为PCTRL_MSG类型并且定义PCTRL_MSG这个结构体内容为

typedef struct
{
    uint8    cmd_head;                    //帧头

    uint8    cmd_type;                    //命令类型(UPDATE_CONTROL)    
    uint8    ctrl_msg;                    //CtrlMsgType-指示消息的类型
    uint16   screen_id;                   //产生消息的画面ID
    uint16   control_id;                  //产生消息的控件ID
    uint8    control_type;                //控件类型

    uint8    param[256];                  //可变长度参数,最多256个字节

    uint8  cmd_tail[4];                   //帧尾
}CTRL_MSG,*PCTRL_MSG;

数据通过强转成这样一个结构体后,利用结构体的偏移特性得知当前使用的是什么控件,并作出相应的处理


接收数据后,单片机处理通过串口返回发送数据给串口屏在hmi_driver.c中实现。

例程定义了一些函数方便编写使用.

#define TX_8(P1) SEND_DATA((P1)&0xFF)                    //发送单个字节
#define TX_8N(P,N) SendNU8((uint8 *)P,N)                 //发送N个字节
#define TX_16(P1) TX_8((P1)>>8);TX_8(P1)                 //发送16位整数
#define TX_16N(P,N) SendNU16((uint16 *)P,N)              //发送N个16位整数
#define TX_32(P1) TX_16((P1)>>16);TX_16((P1)&0xFFFF)     //发送32位整数

#if(CRC16_ENABLE)

static uint16 _crc16 = 0xffff;
/*!
*  \brief 添加CRC16校验
*  \param buffer 待校验的数据
*  \param n 数据长度,包含CRC16
*  \param pcrc 校验码
*/
static void AddCRC16(uint8 *buffer,uint16 n,uint16 *pcrc)
{
    uint16 i,j,carry_flag,a;

    for (i=0; i<n; i++)
    {
        *pcrc=*pcrc^buffer[i];
        for (j=0; j<8; j++)
        {
            a=*pcrc;
            carry_flag=a&0x0001;
            *pcrc=*pcrc>>1;
            if (carry_flag==1)
                *pcrc=*pcrc^0xa001;
        }
    }
}
/*!
*  \brief  检查数据是否符合CRC16校验
*  \param buffer 待校验的数据,末尾存储CRC16
*  \param n 数据长度,包含CRC16
*  \return 校验通过返回1,否则返回0
*/
uint16 CheckCRC16(uint8 *buffer,uint16 n)
{
    uint16 crc0 = 0x0;
    uint16 crc1 = 0xffff;

    if(n>=2)
    {
        crc0 = ((buffer[n-2]<<8)|buffer[n-1]);
        AddCRC16(buffer,n-2,&crc1);
    }

    return (crc0==crc1);
}
/*!
*  \brief  发送一个字节
*  \param  c
*/
void SEND_DATA(uint8 c)
{
    AddCRC16(&c,1,&_crc16);
    SendChar(c);
}
/*!
*  \brief  帧头
*/
void BEGIN_CMD()
{
    TX_8(0XEE);
    _crc16 = 0XFFFF;                      //开始计算CRC16
}
/*!
*  \brief  帧尾
*/
void END_CMD()
{
    uint16 crc16 = _crc16;
    TX_16(crc16);                         //发送CRC16
    TX_32(0XFFFCFFFF);
}

#else//NO CRC16

#define SEND_DATA(P) SendChar(P)          //发送一个字节
#define BEGIN_CMD() TX_8(0XEE)            //帧头
#define END_CMD() TX_32(0XFFFCFFFF)       //帧尾

#endif

这些已经封装好了的函数在以后的编写使用中能够极大的减轻编写难度

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值