由于MCU內(nèi)部資源限制,在應(yīng)用中會(huì)出現(xiàn)UART接口不夠用的情況,如果UART使用的波特率不太高,而且系統(tǒng)中的負(fù)荷不是很大的情況就可以使用端口來(lái)模擬UART的收發(fā),下文是一個(gè)在R5F100LE(RL78)上的具體的實(shí)現(xiàn)方法,這里略去工程的建立過(guò)程,相應(yīng)的驅(qū)動(dòng)程序細(xì)節(jié)可以參考代碼生成器生成的代碼,這里只重點(diǎn)講述代碼生成器配置和軟件UART的實(shí)現(xiàn)。
一、硬件資源準(zhǔn)備
01一個(gè)具有外部邊沿中斷功能的IO口來(lái)做UART的RXD端口,下面是一個(gè)配置的例子,在這里我們使用P137(INTP0),在代碼生成器里選擇INTP0為下降沿中斷,中斷優(yōu)先級(jí)可以任意設(shè)置。

02一個(gè)普通的輸出口來(lái)作為UART的TXD端口。這里選擇P43端口,設(shè)置端口輸出高。

03兩個(gè)可以產(chǎn)生中斷、可以隨時(shí)關(guān)閉啟動(dòng)、定時(shí)間隔可以任意設(shè)定的定時(shí)器,一個(gè)發(fā)送定時(shí)器用于發(fā)送數(shù)據(jù),一個(gè)接收定時(shí)器用于接收數(shù)據(jù)。
將接收定時(shí)器的定時(shí)間隔初始化為1位數(shù)據(jù)的時(shí)長(zhǎng)的一半,比如波特率2400,1位為416.6us,那么定時(shí)器設(shè)置為416.6us/2=208.3us,在這里我們使用了Timer的Channel 1


將發(fā)送定時(shí)器的定時(shí)間隔設(shè)置為1位數(shù)據(jù)時(shí)長(zhǎng),比如波特率2400,1位為416.6us,那么定時(shí)器設(shè)置為416.6us,在這里我們使用Timer的Channel 0。

二、UART接收功能的實(shí)現(xiàn)
01接收的軟件實(shí)現(xiàn)
接收時(shí)我們需要寫(xiě)兩個(gè)中斷函數(shù),在中斷里完成數(shù)據(jù)的接收,接收完畢后設(shè)置一個(gè)標(biāo)志,在主循環(huán)中根據(jù)標(biāo)志來(lái)判斷數(shù)據(jù)是否接收完畢。初始化時(shí)需要打開(kāi)邊沿中斷,關(guān)閉定時(shí)器中斷。
1)邊沿中斷函數(shù)處理
當(dāng)下降沿中斷到來(lái)時(shí),在邊沿中斷函數(shù)里啟動(dòng)接收定時(shí)器,關(guān)閉邊沿中斷。具體程序如下:
左右滑動(dòng)查看完整內(nèi)容
void softuart_rece_port_fall_edge_callback(void) { softuart_rece_state = 0;//接收定時(shí)器進(jìn)入次數(shù)計(jì)數(shù)清零 uart_port_intp_stop();// 關(guān)閉邊沿中斷 start_uart_rece_timer();//打開(kāi)接收定時(shí)器中斷 }
這個(gè)函數(shù)放到r_cg_intc_user.c內(nèi)

2)接收定時(shí)器中斷函數(shù)
每奇數(shù)次進(jìn)入中斷時(shí)(第1,3,5…)進(jìn)行RXD端口的采樣并保存數(shù)據(jù),同時(shí)根據(jù)我們的要求進(jìn)行移位操作(比如LSB或MSB,數(shù)據(jù)長(zhǎng)度是幾位),在偶數(shù)次進(jìn)入中斷時(shí)就直接退出,當(dāng)數(shù)據(jù)接收完成后設(shè)置標(biāo)志,同時(shí)關(guān)閉接收定時(shí)器中斷,打開(kāi)邊沿中斷中斷,具體程序如下,這里我是用的8位數(shù)據(jù)長(zhǎng)度和1個(gè)停止位:
左右滑動(dòng)查看完整內(nèi)容
void softuart_rece_timer_callback(void)
{
static __saddr uint8_t uartrece_shift_reg;
softuart_rece_state++;//進(jìn)入次數(shù)++
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位數(shù)據(jù)位
?{
? ?//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();//關(guān)閉接收定時(shí)器
uart_port_intp_start();//打開(kāi)下降沿中斷
if(uartrece_end_fg ==0)
{
uartrece_data = uartrece_shift_reg;
uartrece_end_fg =1;//設(shè)置接收完畢標(biāo)志
}
}
}
這個(gè)程序要放到r_cg_timer_user.c內(nèi)

3)在主循環(huán)里調(diào)用如下函數(shù)來(lái)判斷是否收到數(shù)據(jù)
左右滑動(dòng)查看完整內(nèi)容
uint8_t get_softuart_rece(uint8_t * buff)
{
if(uartrece_end_fg==1)
{
uartrece_end_fg =0;
*buff = uartrece_data;//將數(shù)據(jù)放入接收緩沖區(qū)
return 1;//說(shuō)明收到數(shù)據(jù)
}
return 0;
}
三、UART發(fā)送功能的實(shí)現(xiàn)
01發(fā)送軟件的實(shí)現(xiàn)
發(fā)送時(shí)需要寫(xiě)一個(gè)發(fā)送定時(shí)器中斷函數(shù),在中斷里完成數(shù)據(jù)發(fā)送,發(fā)送完成后設(shè)置一個(gè)標(biāo)志,在主循環(huán)中判斷,初始化時(shí)需要關(guān)閉發(fā)送定時(shí)器,中斷的代碼如下:
左右滑動(dòng)查看完整內(nèi)容
void softuart_send_callback(void)
{
softuart_send_state++;
if(softuart_send_state==10)//發(fā)送停止位
{
//sampling point 10 stop bit
softuart_send_port_h();
}
else if(softuart_send_state>10)//等待停止位發(fā)送完畢
{
//>11 stop bit send finished
softuart_send_state=0;
stop_uart_send_timer();
}
else//發(fā)送數(shù)據(jù)
{
//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;
}
}
這個(gè)程序要放到r_cg_timer_user.c內(nèi)

當(dāng)需要發(fā)送時(shí),先將發(fā)送端口設(shè)置為低電平,然后開(kāi)啟發(fā)送定時(shí)器,如果正在發(fā)送返回發(fā)送錯(cuò)誤。具體的操作代碼如下:
左右滑動(dòng)查看完整內(nèi)容
uint8_t softuart_send(uint8_t data)
{
if(softuart_send_state!=0)return 0;//數(shù)據(jù)沒(méi)有發(fā)送完畢
softuart_send_state = 1;
DI();
softuart_send_port_l(); //發(fā)送起始位
uartsend_shift_reg=data;//將要發(fā)送的數(shù)據(jù)放到移位寄存器
start_uart_send_timer();//啟動(dòng)UART發(fā)送定時(shí)器
EI();
return 1;
}
四、整個(gè)程序的初始化
由于相應(yīng)硬件的初始化程序在R_Systeminit已經(jīng)調(diào)用過(guò)了,所以我們只用調(diào)用啟動(dòng)程序就行了,為了方便程序的修改,用宏定義重新定義了接口部分。
左右滑動(dòng)查看完整內(nèi)容
#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之前需要先調(diào)用一下如下初始化函數(shù)。
左右滑動(dòng)查看完整內(nèi)容
void softuart_int(void)
{
stop_uart_send_timer();//停止發(fā)送定時(shí)器
stop_uart_rece_timer();//停止接收定時(shí)器
uart_port_intp_stop(); // 邊沿中斷接收停止
softuart_send_port_h(); // TXD端口設(shè)置為高
uart_port_intp_start(); // 允許RXD端口的下降沿中斷
softuart_send_state = 0;
softuart_rece_state = 0;
uartrece_end_fg = 0;
}
注意
1)使用上述方法就可以實(shí)現(xiàn)一個(gè)軟件的UART操作,但是使用過(guò)程中不能有長(zhǎng)時(shí)間的關(guān)閉中斷操作,如果有的話會(huì)影響程序的執(zhí)行。
2)如果通訊波特率發(fā)生變化需要修改定時(shí)器的定時(shí)值。
審核編輯:湯梓紅
-
mcu
+關(guān)注
關(guān)注
147文章
18443瀏覽量
381147 -
中斷
+關(guān)注
關(guān)注
5文章
911瀏覽量
43436 -
定時(shí)器
+關(guān)注
關(guān)注
23文章
3350瀏覽量
121306 -
uart
+關(guān)注
關(guān)注
22文章
1292瀏覽量
105855 -
代碼生成器
+關(guān)注
關(guān)注
0文章
25瀏覽量
9468
發(fā)布評(píng)論請(qǐng)先 登錄
怎么使用代碼生成器進(jìn)行外部喚醒源配置
python生成器
利用LabVIEW代碼生成器簡(jiǎn)化應(yīng)用項(xiàng)目
STM32庫(kù)函數(shù)代碼自動(dòng)生成器V1.2
STM32庫(kù)函數(shù)代碼自動(dòng)生成器正式版
STM32庫(kù)函數(shù)代碼自動(dòng)生成器正式版
python生成器是什么
如何擴(kuò)展自定義功能塊,以及代碼生成器的用法
將使用代碼生成器生成的項(xiàng)目移植到與智能配置器一起使用的項(xiàng)目
個(gè)性化地定制自己的uvm代碼生成器模板和腳本
將使用代碼生成器生成的項(xiàng)目移植到與智能配置器一起使用的項(xiàng)目
RL78的代碼生成器發(fā)布說(shuō)明

代碼生成器配置和軟件UART的實(shí)現(xiàn)
評(píng)論