沁恒MCU串口使用指南
转载注明出处。
沁恒MCU串口使用指南:
适用于WCH的32位MCU和CH559/558单片机
只描述TTL电平的TX+RX形式的常规串口,流控,RS232、RS485不在文章涉及范围之内。
大部分8位机按照标准的51单片机串口操作,建议自行搜索。
分为两部分,串口接收和串口发送:
一、串口发送:
首先摘抄CH573手册描述(请先仔细阅读一下,说不定就看明白了)
发送的时候我们肯定希望发送速率越快越好,我们就要充分利用“发送空中断”。因为CPU速度肯定比串口发送速度快,所以总是会存在CPU等待串口发送完成这一情况。
打个比方,有一辆可以坐8个乘客的小巴士,从公司带人去机场,怎么样最快呢,肯定是每次都坐满发车最快~。那怎么知道司机从机场回来,可以安排下一辆车的人了呢?两种方式:
1、司机给负责人打电话,喊人下来
2、负责人蹲公司门口看司机回来了没有,当然不一定要持续盯着,可以每隔几秒抬头看一下
两种通知方式,相比下肯定是第一种省力一点的,所以对应到串口上:
1、FIFO功能毫无疑问要打开(换成8座小巴士)
2、每次坐满发车(CPU连续填充8个字节)
3、通知方式可选中断(打电话通知)或者查询(蹲门口盯着),这个取决于对于串口连续发送的效率要求,中断方式效率会高,但是会增加系统复杂程度(中断优先级、嵌套等问题),查询效率没那么高,但是系统会简洁一点,同时查一下中断标志的开销不大(抬头看一眼,不怎么影响低头刷手机哈哈哈)
4、通知车回来之后,再安排8个人一起上车,如此循环
代码上上述功能的具体实现(伪代码):
1、
R8_UART1_FCR |= (1<<1);
2、
void UART1_SendString( UINT8 *buf )
{UINT8 i;for(i=0;i<8;i++){R8_UART1_THR = *buf++; }
}
3+4、
查询
void UART1_SendString( PUINT8 buf )
{UINT8 i;for(i=0;i<8;i++){R8_UART1_THR = *buf++;}
}void main(){R8_UART1_IER |= (1<<1); //使能串口空中断
while(1){{//cpu干别的事}if(R8_UART1_IIR & (1<<1)) //THR寄存器空UART1_SendString( buf );
}
}
中断
void main(){R8_UART1_IER |= (1<<1); //使能串口空中断PFIC_EnableIRQ( UART1_IRQn ); //打开串口的中断功能while( 1 );
}__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler( void )
{if(R8_UART1_IIR & (1<<1)) //THR寄存器空UART1_SendString( buf );
}
二、串口接收
串口的接收整体会麻烦很多,因为是被动的。先摘抄手册描述:(同样先仔细阅读一遍)
串口接收首先是个被动的过程,所以我们尽量的用中断来处理。先看一下和接收相关的中断类型:
①接收数据可用:接受的字节数达到FIFO的触发点
②接收数据超时:超过4个字节时间未收到下一数据
这两个中断足以应付绝大部分的场景了。因为串口有8字节的FIFO,进来的数据可以稍微缓冲一下,不至于一有数据就要处理,这会变得挺麻烦的,这点相比标准51单片机来说进步很多。
①接收数据可用中断:
因为数据有可能连续不断的一直发送过来,我们要及时的读取,但是又不能太及时,不然可能影响CPU处理别的东西。
打个比方,有个消毒房间,会从天花板上喷消毒水对工作人员进行消毒,这个消毒房间最多只能站8个人,每隔一分钟都会有人要进入消毒房间,单人单次消毒不到1分钟就可以完成,但是每多一个人多喷洒一小会的消毒水,防止出现死角没有喷洒到药水。所以我们有两种模式进行消毒:
①每来一个人就进去消毒,下一个人来的时候前一个人已经消毒结束了
②等多几个人,然后几个人一起进去消毒,下一个人来的时候几个人一起消毒结束了
两种方式显然都是可以的,但是会有以下的问题,第一种模式会浪费掉更多的药水,每个人都是100%的药水喷洒量,第二种模式平均到每个人的药水用量会节省不少。但是模式二如果进入人数太多,可能消毒所需要的时间会超过1分钟,导致下一个来的人被堵在门口了。所以第二种模式需要根据规则限制人数,防止后来的人堵在门口。
对应到串口接收上,串口每接收到一个数据就去处理当然可以,但是会导致CPU开销变大。启用“接收数据可用”中断能够节约CPU开销,但是可能存在CPU还没有读取FIFO中数据,下一个数据就到来的情况。所以可能当FIFO还没有满的时候,CPU就可以去将数据取出来,防止出现阻塞(对于串口来说实际上就是丢数据了),这时候产生“接收数据可用”中断的产生条件“FIFO触发点”就有价值了:
结合串口波特率、CPU频率配置合适的触发点,设置成4字节会比较保险且高效一点。
伪代码如下:
UINT8 flag=0;
UINT8 buf[4];
void main( ){R8_UART1_FCR = (R8_UART1_FCR & ~(3<<6))) | (2<<6); //设置4字节FIFO触发点R8_UART1_IER |= 1; //使能接收数据可用中断while(1){if(flag){flag = 0;printf("1:%02x\n",buf[0]);printf("2:%02x\n",buf[1]);printf("3:%02x\n",buf[2]);printf("4:%02x\n",buf[3]);}}
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler( void )
{UINT8 i;if(R8_UART1_IIR & (1<<2)){ //中断源为数据接受可用for(i=0;i<4;i++){buf[i] = R8_UART1_RBR; //直接按照触发点长度读取若干次RBR寄存器}flag = 1;}}
②接收数据超时中断:
简单说就是串口空闲了会产生中断,主观上可以认为是一帧结束,配合“数据接收可用”中断。通常数据都是有格式,会有固定长度。假设我们FIFO触发点设置4,数据一帧是14字节,一分钟来一帧数据。我们也有两种方式去接收数据:
1、只判断“数据接收可用“中断,那么这一帧数据会触发3次中断,成功接收到12字节数据,最后剩下的2字节数据会保存在FIFO中,因为2字节不到触发点,所以CPU并不知道要去取数据。直到1分钟之后下一帧数据到来,新一帧的前2字节和前一帧的2字节凑成4字节,新一帧剩余的12字节正好能凑4的整数倍。这样数据倒是不会丢,但是出现了时效性的问题。
2、开启“接收数据超时“中断,处理前面的那种情况,第一帧到来之后,先连续触发3次FIFO触发点,CPU取走12字节数据,剩余2字节在FIFO中储存,串口空闲4字节时间(当前波特率连续发送4字节所需要的时间),产生了超时中断,因为知道一帧数据就是14字节,当产生超时中断时,FIFO中必然有2字节数据,此时直接读取两次RBR寄存器就可以将一整帧接收完成,而不用傻傻等一分钟那么久了。伪代码如下:
UINT8 flag1=0;
UINT8 flag2=0;
UINT8 buf[4];
void main( ){R8_UART1_FCR = (R8_UART1_FCR & ~(3<<6))) | (2<<6); //设置4字节FIFO触发点R8_UART1_IER |= 1; //使能接收数据可用中断while(1){if(flag1){flag1 = 0;printf("1:%02x\n",buf[0]);printf("2:%02x\n",buf[1]);printf("3:%02x\n",buf[2]);printf("4:%02x\n",buf[3]);}if(flag2){flag2 = 0;printf("1:%02x\n",buf[0]);printf("2:%02x\n",buf[1]);}}
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler( void )
{UINT8 i;switch(R8_UART1_IIR & (3<<2)){ case 0x04; //中断源为数据接受可用for(i=0;i<4;i++){buf[i] = R8_UART1_RBR; //直接按照触发点长度读取若干次RBR寄存器}flag1 = 1;break;case 0x0c: //中断源为超时for(i=0;i<2;i++){buf[i] = R8_UART1_RBR; //直接按照触发点长度读取若干次RBR寄存器}flag2 = 1;break;}if(R8_UART1_IIR & (3<<2))
}
总结:
至此一个常规的16C550类串口就能够正常工作起来了,关于FIFO触发点的配置,超时中断的利用,还是要结合串口数据一帧的规律来调整。都看到这里了,其实手册讲的也很挺直白了、、、
`
沁恒MCU串口使用指南相关推荐
- 沁恒MCU从EVT中提取文件建立MounRiver独立工程
沁恒的MCU程序开发包简称EVT,是沁恒官方给出的芯片使用参考例程. EVT开发包为了减少体积,将很多工程的文件复用. 当修改一个公用文件(像link.ld,StdPeriphDriver文件夹中的库 ...
- 沁恒RISC-V MCU 为全国大学生智能汽车竞赛加速
§01 沁恒RISC-V 第十七届(2022年)全国大学生智能汽车竞赛规则已发布,沁恒微电子很荣幸继续为大赛提供赞助.其中多车编队组的头车限定使用沁恒微电子的MCU作为主控,跟随车之一可以选用沁恒 ...
- 全国大学生智能车竞赛申请沁恒RISC-V MCU样品说明
第十六届(2021 年)全国大学生智能汽车竞赛规则已发布,沁恒微电子很荣幸成为大赛的赞助商之一.本次大赛推荐使用的WCH 微控制器CH32V103 为沁恒微电子自主研发的32 位通用RISC-V架 ...
- 开源基于涂鸦模组和沁恒RISC-V 架构32位MCU的IOT物联网生活环境监测系统及涂鸦模组使用
文章目录 前言 一.项目简介 二.硬件介绍 1.硬件原理图 1.1核心板 1.2涂鸦模组 1.3供电电路设计 1.4外设电路 1.4总结 二.涂鸦模块通信协议使用 2.1涂鸦模组协议移植 2.2移植步 ...
- 沁恒全方位提供多种USB串口驱动第3代USB转串口产品
沁恒全方位提供多种USB串口驱动程序供选择,支持Windows/Linux/Android/macOS等操作系统.驱动类型说明: VCP:厂商提供仿真串口驱动,支持各操作系统,功能多,效率高,支持高波 ...
- 参加全国大学生智能汽车竞赛,快来申请沁恒RISC-V MCU!
第十六届(2021年)全国大学生智能汽车竞赛规则已发布,沁恒微电子很荣幸成为大赛的赞助商之一.本次大赛推荐使用的WCH微控制器CH32V103为沁恒微电子自主研发的32位通用RISC-V架构MCU. ...
- 【沁恒WCH CH32V307V-R1的单线半双工模式串口通讯】
[沁恒WCH CH32V307V-R1的单线半双工模式串口通讯] 1. 前言 2. 软件配置 2.1 安装MounRiver Studio 3. UASRT项目测试 3.1 打开UASRT工程 3.2 ...
- 国产沁恒CH32F103C8T6使用指南
国产沁恒CH32F103C8T6使用指南 获取更多内容,请关注微信公众号"电路板上的一抹微笑" 前言: CH32F103芯片是由南京沁恒电子产品公司推出的国产ARM芯片,与STM3 ...
- 串口转HID键盘鼠标芯片沁恒微电子CH9329
概述 沁恒微电子CH9329 是一款串口转标准 USB HID 设备(键盘.鼠标.自定义 HID)芯片,根据不同的工作模式, 在电脑上可被识别为标准的 USB 键盘设备.USB 鼠标设备或自定义 HI ...
- 沁恒CH552G实现最小系统[沁恒8位机MCU最小系统]
转载著名出处. 一.目标: 学习沁恒的8位机最小系统的实现. 最小系统连接方式通用下面所有常规8位MCU 二.资料获取: 1.首先从沁恒官网下载CH552的datasheet: CH552官网手册下载 ...
最新文章
- 57 Node.js异步编程
- 【转】OGRE资源相关分析
- ACL 2016 | CopyNet 和 Pointer Softmax
- idea 新建ssm java ee_IDEA搭建SSM项目实现增删改查
- Table是怎样炼成的:HtmlTable
- 2018年python工作好找吗-2018年最新数据:python、大数据、人工智能从业者薪资表...
- OSChina 周四乱弹 —— 电脑上都有监视器
- mysql recovery_MySQL Recovery
- vs2017下载安装教程
- 小程序投标书_程序员接私活常用哪些平台?
- 学生党直呼哇塞的几个超好用工具
- 幸运的人更幸运 - 节选
- 如何修改网卡的默认dns服务器,DNS怎么设置?DNS设置大全
- Python3 math模块以及运算优先级
- 盘点TMT领域10家国内投资机构
- 蚂蚁金服若IPO 信贷业务或将得到长远发展
- 11.2NOIP模拟赛
- 【愚公系列】2022年02月 微信小程序-Component组件的扩展
- 互联网医疗大数据类型的深度分析
- Android音频开发(1):音频相关知识