GD32F30x gpio 模拟串口之 RXD

上一篇文章中,通过gpio+timer的方式,实现了一个波特率19200的uart_txd。本次带来uart的另一半:RXD。

先看效果展示:

GD32F30x gpio 模拟串口之 RXD_第1张图片

话不多说,上代码:

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时数据接收稳定,设置更高时偶发错误。应用时可以自行优化。

你可能感兴趣的:(MCU_32-Advanced,单片机,c语言,嵌入式硬件)