由于mcu内部资源限制,在应用中会出现uart接口不够用的情况,如果uart使用的波特率不太高,而且系统中的负荷不是很大的情况就可以使用端口来模拟uart的收发,下文是一个在r5f100le(rl78)上的具体的实现方法,这里略去工程的建立过程,相应的驱动程序细节可以参考代码生成器生成的代码,这里只重点讲述代码生成器配置和软件uart的实现。
一、硬件资源准备
01一个具有外部边沿中断功能的io口来做uart的rxd端口,下面是一个配置的例子,在这里我们使用p137(intp0),在代码生成器里选择intp0为下降沿中断,中断优先级可以任意设置。
02一个普通的输出口来作为uart的txd端口。这里选择p43端口,设置端口输出高。
03两个可以产生中断、可以随时关闭启动、定时间隔可以任意设定的定时器,一个发送定时器用于发送数据,一个接收定时器用于接收数据。
将接收定时器的定时间隔初始化为1位数据的时长的一半,比如波特率2400,1位为416.6us,那么定时器设置为416.6us/2=208.3us,在这里我们使用了timer的channel 1
将发送定时器的定时间隔设置为1位数据时长,比如波特率2400,1位为416.6us,那么定时器设置为416.6us,在这里我们使用timer的channel 0。
二、uart接收功能的实现
01接收的软件实现
接收时我们需要写两个中断函数,在中断里完成数据的接收,接收完毕后设置一个标志,在主循环中根据标志来判断数据是否接收完毕。初始化时需要打开边沿中断,关闭定时器中断。
1)边沿中断函数处理
当下降沿中断到来时,在边沿中断函数里启动接收定时器,关闭边沿中断。具体程序如下:
左右滑动查看完整内容
void softuart_rece_port_fall_edge_callback(void){ softuart_rece_state = 0;//接收定时器进入次数计数清零 uart_port_intp_stop();// 关闭边沿中断 start_uart_rece_timer();//打开接收定时器中断}
这个函数放到r_cg_intc_user.c内
2)接收定时器中断函数
每奇数次进入中断时(第1,3,5…)进行rxd端口的采样并保存数据,同时根据我们的要求进行移位操作(比如lsb或msb,数据长度是几位),在偶数次进入中断时就直接退出,当数据接收完成后设置标志,同时关闭接收定时器中断,打开边沿中断中断,具体程序如下,这里我是用的8位数据长度和1个停止位:
左右滑动查看完整内容
void softuart_rece_timer_callback(void){static __saddr uint8_t uartrece_shift_reg; softuart_rece_state++;//进入次数++ if(softuart_rece_state==1)//接收start位 { //check start bit if(1==get_uart_rece_port()) { //start bit error uartrece_shift_reg = 0; stop_uart_rece_timer(); uart_port_intp_start(); } } else if (softuart_rece_state>= 1; if(1==get_uart_rece_port()) { uartrece_shift_reg |= 0x80; } } else if(softuart_rece_state>=19)//接收停止位 { //stop bit sample sampling point 19 stop_uart_rece_timer();//关闭接收定时器 uart_port_intp_start();//打开下降沿中断 if(uartrece_end_fg ==0) { uartrece_data = uartrece_shift_reg; uartrece_end_fg =1;//设置接收完毕标志 } }}
这个程序要放到r_cg_timer_user.c内
3)在主循环里调用如下函数来判断是否收到数据
左右滑动查看完整内容
uint8_t get_softuart_rece(uint8_t * buff){ if(uartrece_end_fg==1) { uartrece_end_fg =0; *buff = uartrece_data;//将数据放入接收缓冲区 return 1;//说明收到数据 } return 0;}
三、uart发送功能的实现
01发送软件的实现
发送时需要写一个发送定时器中断函数,在中断里完成数据发送,发送完成后设置一个标志,在主循环中判断,初始化时需要关闭发送定时器,中断的代码如下:
左右滑动查看完整内容
void softuart_send_callback(void){ softuart_send_state++; if(softuart_send_state==10)//发送停止位 { //sampling point 10 stop bit softuart_send_port_h(); } else if(softuart_send_state>10)//等待停止位发送完毕 { //>11 stop bit send finished softuart_send_state=0; stop_uart_send_timer(); } else//发送数据 { //samplimng point 2,3,4,5,6,7,8,9 if(0!=(uartsend_shift_reg&1)) { softuart_send_port_h(); } else { softuart_send_port_l(); } uartsend_shift_reg >>= 1; }}
这个程序要放到r_cg_timer_user.c内
当需要发送时,先将发送端口设置为低电平,然后开启发送定时器,如果正在发送返回发送错误。具体的操作代码如下:
左右滑动查看完整内容
uint8_t softuart_send(uint8_t data){ if(softuart_send_state!=0)return 0;//数据没有发送完毕 softuart_send_state = 1; di(); softuart_send_port_l(); //发送起始位 uartsend_shift_reg=data;//将要发送的数据放到移位寄存器 start_uart_send_timer();//启动uart发送定时器 ei(); return 1;}
四、整个程序的初始化
由于相应硬件的初始化程序在r_systeminit已经调用过了,所以我们只用调用启动程序就行了,为了方便程序的修改,用宏定义重新定义了接口部分。
左右滑动查看完整内容
#define start_uart_rece_timer() r_tau0_channel1_start()#define stop_uar_rece_timer() r_tau0_channel1_stop()#define uart_port_intp_start() r_intc0_start()#define uart_port_intp_stop() r_intc0_stop()#define get_uart_rece_port() p13_bit.no7#define start_uart_send_timer() r_tau0_channel0_start()#define stop_uart_send_timer() r_tau0_channel0_stop()#define softuart_send_port_h() {p4_bit.no3 = 1;}#define softuart_send_port_l() {p4_bit.no3 = 0;}
如果想要修改使用的硬件资源只用修改宏定义即可。
在使用软件uart之前需要先调用一下如下初始化函数。
左右滑动查看完整内容
void softuart_int(void){ stop_uart_send_timer();//停止发送定时器 stop_uart_rece_timer();//停止接收定时器 uart_port_intp_stop(); // 边沿中断接收停止 softuart_send_port_h(); // txd端口设置为高 uart_port_intp_start(); // 允许rxd端口的下降沿中断 softuart_send_state = 0; softuart_rece_state = 0; uartrece_end_fg = 0;}
注意
1)使用上述方法就可以实现一个软件的uart操作,但是使用过程中不能有长时间的关闭中断操作,如果有的话会影响程序的执行。
2)如果通讯波特率发生变化需要修改定时器的定时值。
如何做一部基于STM32F4的手持式游戏机
快讯:汉诺威工业展起跑,聚焦人工智能与5G
华人卫视携手玉银能公司打造区块链+艺术品资产化交易服务平台
CEE国际消费电子展多管齐下打造行业发展年度盛典
OPPO开发者大会2021 colorOS的AON全天候视觉感知服务
代码生成器配置和软件UART的实现
虹科与Dimetix合作三年, 致力提供精确的测距解决方案
工业自控流程对传感器有哪些不同需求?
台湾远翔电源管理芯片
霍尔电流传感器如何测量电流
小米mix2什么时候上市 小米mix2价格是多少?
如何用常用的耐压绝缘测试测量AC/DC转换器隔离电压
中国互联网行业错失一个超级大BOSS平台,该高兴还是该懊悔呢?
微软推出一系列MagSafe游戏配件
基于单/双核Zynq的GigaExpress SBC PCIe卡
基于Vitis AI的ADAS目标识别
高通摊上大事,被台湾罚款51亿,估计只是说说而已
【节能学院】用电预付费系统在工业园区物业管理中的应用
晶体知识:位错的基本类型和特征
基于SiC功率模块的高效逆变器设计方案