
由于MCU內部資源限制,在應用中會出現UART接口不夠用的情況,如果UART使用的波特率不太高,而且系統中的負荷不是很大的情況就可以使用端口來模擬UART的收發,下文是一個在R5F100LE(RL78)上的具體的實現方法,這里略去工程的建立過程,相應的驅動程序細節可以參考代碼生成器生成的代碼,這里只重點講述代碼生成器配置和軟件UART的實現。


將接收定時器的定時間隔初始化為1位數據的時長的一半,比如波特率2400,1位為416.6us,那么定時器設置為416.6us/2=208.3us,在這里我們使用了Timer的Channel 1


將發送定時器的定時間隔設置為1位數據時長,比如波特率2400,1位為416.6us,那么定時器設置為416.6us,在這里我們使用Timer的Channel 0。

接收時我們需要寫兩個中斷函數,在中斷里完成數據的接收,接收完畢后設置一個標志,在主循環中根據標志來判斷數據是否接收完畢。初始化時需要打開邊沿中斷,關閉定時器中斷。
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<=17)//接收8位數據位?{? ?//receive data sampling point 3,5,7,9,11,13,15,17? ?if(0==(softuart_rece_state&1)) return;? uartrece_shift_reg >>= 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;}
發送時需要寫一個發送定時器中斷函數,在中斷里完成數據發送,發送完成后設置一個標志,在主循環中判斷,初始化時需要關閉發送定時器,中斷的代碼如下:
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已經調用過了,所以我們只用調用啟動程序就行了,為了方便程序的修改,用宏定義重新定義了接口部分。
如果想要修改使用的硬件資源只用修改宏定義即可。
在使用軟件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)如果通訊波特率發生變化需要修改定時器的定時值。
1
END
1
推薦閱讀
使用QE和CS+調試觸摸按鍵
新品開箱 | RL78/G15開發板開箱與開發環境搭建
RL78系列MCU Data Flash使用介紹