当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]超详细总结,值得一看!


微信公众号:morixinguan
关注可了解更多的教程。问题或建议,请公众号留言;
如果你觉得本文对你有帮助,欢迎赞赏


▲长按图片保存可分享至朋友圈


大彩科技是专注做串口屏的厂家,网址如下:

http://www.gz-dc.com/

指令格式如下:

一般情况下,采用的是CRC格式校验的指令。

处理指令方面,大彩提供了一个例程,主要用一个队列来维护。

数据结构:

 1#define QUEUE_MAX_SIZE 128 /*!< 指令接收缓冲区大小,根据需要调整,尽量设置大一些*/  2typedef struct _QUEUE  3{  4 qsize _head; //队列头  5 qsize _tail; //队列尾  6 qdata _data[QUEUE_MAX_SIZE]; //队列数据缓存区  7}QUEUE;  8  9static QUEUE que = {0,0,0}; //指令队列 10static uint32 cmd_state = 0; //队列帧尾检测状态 11static qsize cmd_pos = 0; //当前指令指针位置 

操作队列的接口有:

 1/*!  2 *  \brief  清空指令数据  3 */  4extern void queue_reset(void);  5  6/*!  7 * \brief  添加指令数据  8 * \detial 串口接收的数据,通过此函数放入指令队列  9 *  \param  _data 指令数据 10 */ 11extern void queue_push(qdata _data); 12 13/*! 14 *  \brief  从指令队列中取出一条完整的指令 15 *  \param  cmd 指令接收缓存区 16 *  \param  buf_len 指令接收缓存区大小 17 *  \return  指令长度,0表示队列中无完整指令 18 */ 19extern qsize queue_find_cmd(qdata *cmd,qsize buf_len);

队列清空的实现很简单,只要把队列头和队队列尾检查状态、当前指针的位置置为0即可,实现如下:

1void queue_reset() 2{ 3 que._head = que._tail = 0; 4 cmd_pos = cmd_state = 0; 5}

添加指令数据操作,其实就是入队的操作,也就是把数据源源不断的放到队列的缓存区中去:

1void queue_push(qdata _data) 2{ 3 qsize pos = (que._head+1)%QUEUE_MAX_SIZE; 4 if(pos!=que._tail)//非满状态 5 { 6 que._data[que._head] = _data; 7 que._head = pos; 8 } 9}

从指令队列中取出一条完整的指令其实就是出队操作,先将数据出队,然后根据指令格式帧进行分割处理。

 1//从队列中取一个数据  2static void queue_pop(qdata* _data)  3{  4 if(que._tail!=que._head)//非空状态  5 {  6 *_data = que._data[que._tail];  7 que._tail = (que._tail+1)%QUEUE_MAX_SIZE;  8 }  9} 10 11qsize queue_find_cmd(qdata *buffer,qsize buf_len) 12{ 13 qsize cmd_size = 0; 14 qdata _data = 0; 15 while(queue_size()>0) 16 { 17 //取一个数据 18 queue_pop(&_data); 19 20 if(cmd_pos==0&&_data!=CMD_HEAD)//指令第一个字节必须是帧头,否则跳过 21 continue; 22 23 if(cmd_pos//防止缓冲区溢出 24 buffer[cmd_pos++] = _data; 25 26 cmd_state = ((cmd_state<<8)|_data);//拼接最后4个字节,组成一个32位整数 27 28 //最后4个字节与帧尾匹配,得到完整帧 29 if(cmd_state==CMD_TAIL) 30 { 31 cmd_size = cmd_pos; //指令字节长度 32 cmd_state = 0; //重新检测帧尾巴 33 cmd_pos = 0; //复位指令指针 34 35#if(CRC16_ENABLE) 36 //去掉指令头尾EE,尾FFFCFFFF共计5个字节,只计算数据部分CRC 37 if(!CheckCRC16(buffer+1,cmd_size-5))//CRC校验 38 return 0; 39 40 cmd_size -= 2;//去掉CRC16(2字节) 41#endif 42 43 return cmd_size; 44 } 45 } 46 47 return 0;//没有形成完整的一帧 48}

那么具体在哪里入队呢?在大彩提供的例程中,入队操作是在串口中断服务函数中进行的:

1void USART1_IRQHandler(void) 2{ 3 if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 4 { 5 uint8_t data = USART_ReceiveData(USART1); 6 queue_push(data); 7 } 8}

在这期间主要发生两个操作:

1、串口通过中断接收一个字节

2、将接收到的每一个字节放入队列缓存区中

那么又具体怎么知道串口屏给我回复的指令呢,然后发生一系列动作呢?

这时候,程序里需要有一个while(1),源源不断的等待queue_find_cmd函数给我们做取数据,完成拼接指令的过程。

 1....  2while(1)  3{  4 size = queue_find_cmd(cmd_buffer,CMD_MAX_SIZE); //从缓冲区中获取一条指令   5 if(size>0)//接收到指令  6 {  7 ProcessMessage((PCTRL_MSG)cmd_buffer, size);//指令处理  8 }  9} 10....

cmd_buffer在这里就是一条完整的指令,再将这条完整的指令传入ProcessMessage函数,对指令进行处理,其中将数据强转为PCTRL_MSG这个数据结构,主要为:

 1typedef struct  2{  3 uint8 cmd_head; //帧头  4  5 uint8 cmd_type; //命令类型(UPDATE_CONTROL)   6 uint8 ctrl_msg; //CtrlMsgType-指示消息的类型  7 uint8 screen_id_high; //产生消息的画面ID  8 uint8 screen_id_low;  9 uint8 control_id_high; //产生消息的控件ID 10 uint8 control_id_low; 11 uint8 control_type; //控件类型 12 13 uint8 param[256];//可变长度参数,最多256个字节 14 15 uint8 cmd_tail[4]; //帧尾 16}CTRL_MSG,*PCTRL_MSG;

在这里接收到的cmd_buffer里的指令是把头尾去掉的,这时候我们明白了,接收过来的指令需要赋给它一定的含义,于是看ProcessMessage函数的实现:

 1/*!  2 *  \brief  消息处理流程,此处一般不需要更改  3 *  \param msg 待处理消息  4 *  \param size 消息长度  5 */  6void ProcessMessage( PCTRL_MSG msg, uint16 size )  7{  8 uint8 cmd_type = msg->cmd_type;//指令类型  9 uint8 ctrl_msg = msg->ctrl_msg; //消息的类型 10 uint8 control_type = msg->control_type;//控件类型 11 uint16 screen_id = PTR2U16(&msg->screen_id_high);//画面ID 12 uint16 control_id = PTR2U16(&msg->control_id_high);//控件ID 13 uint32 value = PTR2U32(msg->param);//数值 14 15 switch(cmd_type) 16 { 17 case NOTIFY_TOUCH_PRESS://触摸屏按下 18 case NOTIFY_TOUCH_RELEASE://触摸屏松开 19 NotifyTouchXY(cmd_buffer[1],PTR2U16(cmd_buffer+2),PTR2U16(cmd_buffer+4)); 20 break; 21 case NOTIFY_WRITE_FLASH_OK://写FLASH成功 22 NotifyWriteFlash(1); 23 break; 24 case NOTIFY_WRITE_FLASH_FAILD://写FLASH失败 25 NotifyWriteFlash(0); 26 break; 27 case NOTIFY_READ_FLASH_OK://读取FLASH成功 28 NotifyReadFlash(1,cmd_buffer+2,size-6);//去除帧头帧尾 29 break; 30 case NOTIFY_READ_FLASH_FAILD://读取FLASH失败 31 NotifyReadFlash(0,0,0); 32 break; 33 case NOTIFY_READ_RTC://读取RTC时间 34 NotifyReadRTC(cmd_buffer[1],cmd_buffer[2],cmd_buffer[3],cmd_buffer[4],cmd_buffer[5],cmd_buffer[6],cmd_buffer[7]); 35 break; 36 case NOTIFY_CONTROL: 37 { 38 if(ctrl_msg==MSG_GET_CURRENT_SCREEN)//画面ID变化通知 39 { 40 NotifyScreen(screen_id); 41 } 42 else 43 { 44 switch(control_type) 45 { 46 case kCtrlButton: //按钮控件 47 NotifyButton(screen_id,control_id,msg->param[1]); 48 break; 49 case kCtrlText://文本控件 50 NotifyText(screen_id,control_id,msg->param); 51 break; 52 case kCtrlProgress: //进度条控件 53 NotifyProgress(screen_id,control_id,value); 54 break; 55 case kCtrlSlider: //滑动条控件 56 NotifySlider(screen_id,control_id,value); 57 break; 58 case kCtrlMeter: //仪表控件 59 NotifyMeter(screen_id,control_id,value); 60 break; 61 case kCtrlMenu://菜单控件 62 NotifyMenu(screen_id,control_id,msg->param[0],msg->param[1]); 63 break; 64 case kCtrlSelector://选择控件 65 NotifySelector(screen_id,control_id,msg->param[0]); 66 break; 67 case kCtrlRTC://倒计时控件 68 NotifyTimer(screen_id,control_id); 69 break; 70 default: 71 break; 72 } 73 } 74 } 75 break; 76 default: 77 break; 78 } 79}

这里学习到了一个编程的小技巧,将数据强转为一个结构体,再利用结构体的偏移特性来获得数据。
这个函数的作用就显而易见了,通过一条指令得知当前使用的是什么控件等等。。。

发送指令就很简单了,其实就是直接给串口发数据,这里是实现如何发送数据给串口的定义:

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

这里是参考手册发送的指令:

 1#if(CRC16_ENABLE)  2  3static uint16 _crc16 = 0xffff;  4static void AddCRC16(uint8 *buffer,uint16 n,uint16 *pcrc)  5{  6 uint16 i,j,carry_flag,a;  7  8 for (i=0; i 9 { 10 *pcrc=*pcrc^buffer[i]; 11 for (j=0; j<8; j++) 12 { 13 a=*pcrc; 14 carry_flag=a&0x0001; 15 *pcrc=*pcrc>>1; 16 if (carry_flag==1) 17 *pcrc=*pcrc^0xa001; 18 } 19 } 20} 21 22uint16 CheckCRC16(uint8 *buffer,uint16 n) 23{ 24 uint16 crc0 = 0x0; 25 uint16 crc1 = 0xffff; 26 27 if(n>=2) 28 { 29 crc0 = ((buffer[n-2]<<8)|buffer[n-1]); 30 AddCRC16(buffer,n-2,&crc1); 31 } 32 33 return (crc0==crc1); 34} 35 36void SEND_DATA(uint8 c) 37{ 38 AddCRC16(&c,1,&_crc16); 39 SendChar(c); 40} 41 42void BEGIN_CMD() 43{ 44 TX_8(0XEE); 45 _crc16 = 0XFFFF;//开始计算CRC16 46} 47 48void END_CMD() 49{ 50 uint16 crc16 = _crc16; 51 TX_16(crc16);//发送CRC16 52 TX_32(0XFFFCFFFF); 53} 54 55#else//NO CRC16 56 57#define SEND_DATA(P) SendChar(P) 58#define BEGIN_CMD() TX_8(0XEE) 59#define END_CMD() TX_32(0XFFFCFFFF) 60 61#endif 62 63void DelayMS(unsigned int n) 64{ 65 int i,j; 66 for(i = n;i>0;i--) 67 for(j=1000;j>0;j--) ; 68} 69 70void SendStrings(uchar *str) 71{ 72 while(*str) 73 { 74 TX_8(*str); 75 str++; 76 } 77} 78 79void SendNU8(uint8 *pData,uint16 nDataLen) 80{ 81 uint16 i = 0; 82 for (;i83 { 84 TX_8(pData[i]); 85 } 86} 87 88void SendNU16(uint16 *pData,uint16 nDataLen) 89{ 90 uint16 i = 0; 91 for (;i92 { 93 TX_16(pData[i]); 94 } 95}


长期商务合作服务:



免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭