上一篇文章中,通过gpio+timer的方式,实现了一个波特率19200的uart_txd。本次带来uart的另一半:RXD。
先看效果展示:
话不多说,上代码:
uart_sw.h
#ifndef SOFTWARE_UART_H
#define SOFTWARE_UART_H
#include "gd32f30x_it.h"
#include "main.h"
#include "systick.h"
#include "gd32f30x.h"
#include "gd32f30x_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UART_SW_RXD_BAUDRATE (4800U)
#define UART_SW_TXD_BAUDRATE (19200U)
#define UART_SEND_MAX_LEN 100
typedef enum __uart_recv_status_t{
UART_RECV_STATUS_IDLE = 0,
UART_RECV_STATUS_START,
UART_RECV_STATUS_RECVING,
}uart_recv_status_t;
typedef enum __uart_recv_bit_t{
UART_RECV_START_BIT = 0,
UART_RECV_D0_BIT,
UART_RECV_D1_BIT,
UART_RECV_D2_BIT,
UART_RECV_D3_BIT,
UART_RECV_D4_BIT,
UART_RECV_D5_BIT,
UART_RECV_D6_BIT,
UART_RECV_D7_BIT,
UART_RECV_STOP_BIT,
}uart_recv_bit_t;
typedef enum __uart_rx_timer_state_t{
UART_RX_TIMER_HALF = 0,
UART_RX_TIMER_FULL,
}uart_rx_timer_state_t;
typedef struct __uart_sw_t{
rcu_periph_enum rx_gpio_RCU;
uint32_t rx_gpio_periph;
uint32_t rx_pin;
uint8_t rx_exti_source_port;
uint8_t rx_exti_source_pin;
uint8_t rx_exti_irq;
exti_line_enum rx_linex;
rcu_periph_enum rx_timer_RCU;
uint32_t rx_timer_prescaler;
uint32_t rx_timer_period;
uint32_t rx_timer_periph;
uint8_t rx_timer_nvic_irq;
uint16_t recv_cnt;
uart_recv_bit_t recv_bit;
uart_recv_status_t uart_recv_status;
uint8_t rx_buf[UART_SEND_MAX_LEN];
void (*rx_init)(void);
void (*adj_rx_timer)(uint32_t);
void (*start_rx_timer)(void);
void (*stop_rx_timer)(void);
void (*start_rx_exti)(void);
void (*stop_rx_exti)(void);
}uart_sw_t;
void uart_sw_adjust_timer(uint32_t period);
void uart_sw_set_in_rx_exti(void);
void uart_sw_set_in_rx_timer(void);
void uart_sw_set_in_loop(void);
#ifdef __cplusplus
}
#endif
#endif /* SOFTWARE_UART_H */
uart_sw.c
#include "software_uart.h"
#include "RTTInit.h"
#include "string.h"
#include "sdk_common.h"
void uart_sw_rx_init(void);
void uart_sw_start_rx_timer(void);
void uart_sw_stop_rx_timer(void);
void uart_sw_start_rx_exti(void);
void uart_sw_stop_rx_exti(void);
//4800
uart_sw_t uart_sw = {
.rx_gpio_RCU = RCU_GPIOB,
.rx_gpio_periph = GPIOB,
.rx_pin = GPIO_PIN_4,
.rx_exti_source_port= GPIO_PORT_SOURCE_GPIOB,
.rx_exti_source_pin = GPIO_PIN_SOURCE_4,
.rx_exti_irq = EXTI4_IRQn,
.rx_linex = EXTI_4,
.rx_timer_RCU = RCU_TIMER6,
.rx_timer_periph = TIMER6,
.rx_timer_prescaler = 74,
.rx_timer_period = 199,
.rx_timer_nvic_irq = TIMER6_IRQn,
.recv_cnt = 0,
.recv_bit = UART_RECV_START_BIT,
.uart_recv_status = UART_RECV_STATUS_IDLE,
.rx_buf = {0},
.rx_init = uart_sw_rx_init,
.start_rx_timer = uart_sw_start_rx_timer,
.stop_rx_timer = uart_sw_stop_rx_timer,
.start_rx_exti = uart_sw_start_rx_exti,
.stop_rx_exti = uart_sw_stop_rx_exti,
.adj_rx_timer = uart_sw_adjust_timer,
};
void uart_sw_rx_init(void){
rcu_periph_clock_enable(uart_sw.rx_gpio_RCU);
rcu_periph_clock_enable(RCU_AF);
gpio_init(uart_sw.rx_gpio_periph, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, uart_sw.rx_pin);
nvic_irq_enable(uart_sw.rx_exti_irq, 7U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(uart_sw.rx_exti_source_port, uart_sw.rx_exti_source_pin);
/* configure key EXTI line */
exti_init(uart_sw.rx_linex, EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(uart_sw.rx_linex);
/* enable the timer3 clock */
rcu_periph_clock_enable(uart_sw.rx_timer_RCU);
timer_deinit(uart_sw.rx_timer_periph);
/* configure timer3 */
timer_parameter_struct rx_timer;
timer_struct_para_init(&rx_timer);
rx_timer.prescaler = uart_sw.rx_timer_prescaler;
rx_timer.alignedmode = TIMER_COUNTER_EDGE;
rx_timer.counterdirection = TIMER_COUNTER_UP;
rx_timer.period = uart_sw.rx_timer_period;
rx_timer.clockdivision = TIMER_CKDIV_DIV1;
timer_init(uart_sw.rx_timer_periph, &rx_timer);
/* enable the TIMER3 interrupt */
nvic_irq_enable(uart_sw.rx_timer_nvic_irq, 6, 0);
/* enable TIMER3 */
timer_interrupt_enable(uart_sw.rx_timer_periph,TIMER_INT_UP);
}
void uart_sw_start_rx_timer(void){
timer_interrupt_enable(uart_sw.rx_timer_periph, TIMER_INT_UP);
timer_enable(uart_sw.rx_timer_periph);
}
void uart_sw_stop_rx_timer(void){
timer_disable(uart_sw.rx_timer_periph);
}
void uart_sw_start_rx_exti(void){
nvic_irq_enable(uart_sw.rx_exti_irq, 7U, 0U);
}
void uart_sw_stop_rx_exti(void){
nvic_irq_disable(uart_sw.rx_exti_irq);
}
void uart_sw_adjust_timer(uint32_t period) {
timer_autoreload_value_config(TIMER6, period);
}
void uart_sw_set_in_rx_exti(void) {
if (uart_sw.uart_recv_status == UART_RECV_STATUS_IDLE) {
uart_sw.uart_recv_status = UART_RECV_STATUS_START;
uart_sw.stop_rx_exti();
uart_sw.adj_rx_timer((uart_sw.rx_timer_period + 1) / 2 - 1);
uart_sw.start_rx_timer();
uart_sw.recv_bit = UART_RECV_START_BIT;
}
}
__STATIC_INLINE FlagStatus get_rx_state(void) {
return gpio_input_bit_get(uart_sw.rx_gpio_periph, uart_sw.rx_pin);
};
void uart_sw_set_in_rx_timer(void) {
static uint8_t recv_data = 0;
switch (uart_sw.uart_recv_status) {
case UART_RECV_STATUS_IDLE:
return;
case UART_RECV_STATUS_START:
switch (get_rx_state()) {
case SET:
uart_sw.stop_rx_timer();
uart_sw.uart_recv_status = UART_RECV_STATUS_IDLE;
uart_sw.start_rx_exti();
return;
case RESET:
uart_sw.uart_recv_status = UART_RECV_STATUS_RECVING;
uart_sw.adj_rx_timer(uart_sw.rx_timer_period);
break;
}
break;
case UART_RECV_STATUS_RECVING:
uart_sw.recv_bit++;
if (uart_sw.recv_bit == UART_RECV_STOP_BIT) {
uart_sw.recv_bit = UART_RECV_START_BIT;
uart_sw.stop_rx_timer();
uart_sw.uart_recv_status = UART_RECV_STATUS_IDLE;
uart_sw.start_rx_exti();
uart_sw.rx_buf[uart_sw.recv_cnt++] = recv_data;
// printf("recv_data 0x%X\n", recv_data);//get the current byte
recv_data = 0;
return;
}
switch (get_rx_state()) {
case SET: recv_data |= (1 << (uart_sw.recv_bit - 1));break;
case RESET: recv_data &= ~(1 << (uart_sw.recv_bit - 1));break;
}
// recv_data>>=1;
// if(get_rx_state())
// {
// recv_data |= 0x80;
// }
break;
}
}
void uart_sw_set_in_loop(void) {
static uint16_t rx_cnt_temp = 0;
static float timer_counter_start = 0.0f, timer_counter_end = 0.0f;
if (rx_cnt_temp != uart_sw.recv_cnt) {
rx_cnt_temp = uart_sw.recv_cnt;
timer_counter_start = sdk_hw_get_systick() * 1.0f / 1000;
}
if (rx_cnt_temp == uart_sw.recv_cnt && uart_sw.recv_cnt != 0) {
timer_counter_end = sdk_hw_get_systick() * 1.0f / 1000 - timer_counter_start;
if (timer_counter_end >= 0.01f) {
printBuf("recv", uart_sw.rx_buf, uart_sw.recv_cnt, 8);//show the splited data package in RTT_Viewer
memset(uart_sw.rx_buf, 0, uart_sw.recv_cnt);
uart_sw.recv_cnt = 0;
rx_cnt_temp = 0;
}
}
}
xxxxx_it.c
void TIMER6_IRQHandler(void) {
if(SET == timer_interrupt_flag_get(uart_sw.rx_timer_periph, TIMER_INT_UP)) {
/* clear update interrupt bit */
timer_interrupt_flag_clear(uart_sw.rx_timer_periph, TIMER_INT_UP);
/* toggle selected led */
uart_sw_set_in_rx_timer();
}
}
void EXTI4_IRQHandler(void) {
if (SET == exti_interrupt_flag_get(uart_sw.rx_linex)) {
exti_interrupt_flag_clear(uart_sw.rx_linex);
uart_sw_set_in_rx_exti();
}
}
demo in main.c
void main() {
...
uart_sw.rx_init();
...
while(1) {
...
uart_sw_set_in_loop();
...
}
}
因为当前项目较为复杂,应用定时器也较多,目前实测波特率设置为19200时数据接收稳定,设置更高时偶发错误。应用时可以自行优化。