ARM32开发——串口输入

🎬 秋野酱:《个人主页》

🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

文章目录

需求

串口接收PC机发送的数据。

串口数据接收

csharp 复制代码
static void USART_config() {
    uint32_t usartx_tx_rcu = RCU_GPIOA;
    uint32_t usartx_tx_port = GPIOA;
    uint32_t usartx_tx_pin = GPIO_PIN_9;
    uint32_t usartx_tx_af = GPIO_AF_7;

    uint32_t usartx_rx_rcu = RCU_GPIOA;
    uint32_t usartx_rx_port = GPIOA;
    uint32_t usartx_rx_pin = GPIO_PIN_10;
    uint32_t usartx_rx_af = GPIO_AF_7;

    uint32_t usartx = USART0;
    uint32_t usartx_rcu = RCU_USART0;
    uint32_t usartx_irqn = USART0_IRQn;

    uint32_t usartx_p_baudrate = 115200;
    uint32_t usartx_p_parity = USART_PM_NONE;
    uint32_t usartx_p_wl = USART_WL_8BIT;
    uint32_t usartx_p_stop_bit = USART_STB_1BIT;
    uint32_t usartx_p_data_first = USART_MSBF_LSB;

    /************** gpio config **************/
    // tx
    rcu_periph_clock_enable(usartx_tx_rcu);	// 配置时钟
    gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
    gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
    gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);
    // rx
    rcu_periph_clock_enable(usartx_rx_rcu); // 配置时钟
    gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
    gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
    gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);

    /************** usart config **************/
    // 串口时钟
    rcu_periph_clock_enable(RCU_USART0);
    // USART复位
    usart_deinit(usartx);

    usart_baudrate_set(usartx, usartx_p_baudrate);	// 波特率
    usart_parity_config(usartx, usartx_p_parity); // 校验位
    usart_word_length_set(usartx, usartx_p_wl); // 数据位数
    usart_stop_bit_set(usartx, usartx_p_stop_bit); // 停止位
    usart_data_first_config(usartx, usartx_p_data_first); // 先发送高位还是低位

    // 发送功能配置
    usart_transmit_config(usartx, USART_TRANSMIT_ENABLE); 

    // 接收功能配置
    usart_receive_config(usartx, USART_RECEIVE_ENABLE);
    // 接收中断配置
    nvic_irq_enable(usartx_irqn, 2, 2);
    // usart int rbne
    usart_interrupt_enable(usartx, USART_INT_RBNE);
    usart_interrupt_enable(usartx, USART_INT_IDLE);

    // 使能串口
    usart_enable(usartx); 
}
csharp 复制代码
#define USART_RECEIVE_LENGTH  1024
//串口接收缓冲区大小
uint8_t g_recv_buff[USART_RECEIVE_LENGTH];   // 接收缓冲区
//接收到字符存放的位置
int g_recv_length = 0;

void USART0_IRQHandler(void) {
    if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
        uint16_t value = usart_data_receive(USART0);
        g_recv_buff[g_recv_length] = value;		
        g_recv_length++;
    }
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
        //读取缓冲区,清空缓冲区
        usart_data_receive(USART0);
        g_recv_buff[g_recv_length] = '\0';

        // TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度

        g_recv_length = 0;
    }
}

中断函数

  1. 中断函数的名称是在CMSIS的汇编接口中定义的

  2. 中断触发需要进行配置

csharp 复制代码
......
// 接收功能配置
usart_receive_config(usartx, USART_RECEIVE_ENABLE);
// 接收中断配置
nvic_irq_enable(usartx_irqn, 2, 2);
// usart int rbne
usart_interrupt_enable(usartx, USART_INT_RBNE);
usart_interrupt_enable(usartx, USART_INT_IDLE);
......

IDLE中断

当检测到RX引脚空闲(高电平)时间超过传输一个字符帧所需的时间时,产生空闲标志IDLE

串口接收流程(了解)

寄存器与电路。

  1. 数据接收缓存寄存器(接收和发送其实公用一个寄存器)
  2. 状态寄存器
    外部通过串口发送数据到MCU中来时,首先会把高低电平进行转换为单个byte,接着存储到这个缓存寄存器,存储一个byte的时候,会改变寄存器状态,然后会触发中断,我们在中断中,我们就知道接收到了一个byte,我们就可以去数据接收缓存寄存器中取数据,取完后,接收方又去存,这样周而复始的进行接收。知道外部不发送数据了,这个时候如果长期没有收到数据,就会触发闲置寄存器标记。

完整示例

csharp 复制代码
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"

/**
PA9		TXD
PA10	RXD
**/

#define USART_RECEIVE_LENGTH  1024
//串口接收缓冲区大小
uint8_t g_recv_buff[USART_RECEIVE_LENGTH];   // 接收缓冲区
//接收到字符存放的位置
int g_recv_length = 0;

static void USART_config() {
    uint32_t usartx_tx_rcu = RCU_GPIOA;
    uint32_t usartx_tx_port = GPIOA;
    uint32_t usartx_tx_pin = GPIO_PIN_9;
    uint32_t usartx_tx_af = GPIO_AF_7;

    uint32_t usartx_rx_rcu = RCU_GPIOA;
    uint32_t usartx_rx_port = GPIOA;
    uint32_t usartx_rx_pin = GPIO_PIN_10;
    uint32_t usartx_rx_af = GPIO_AF_7;

    uint32_t usartx = USART0;
    uint32_t usartx_rcu = RCU_USART0;
    uint32_t usartx_irqn = USART0_IRQn;

    uint32_t usartx_p_baudrate = 115200;
    uint32_t usartx_p_parity = USART_PM_NONE;
    uint32_t usartx_p_wl = USART_WL_8BIT;
    uint32_t usartx_p_stop_bit = USART_STB_1BIT;
    uint32_t usartx_p_data_first = USART_MSBF_LSB;

    /************** gpio config **************/
    // tx
    rcu_periph_clock_enable(usartx_tx_rcu);	// 配置时钟
    gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
    gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
    gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);
    // rx
    rcu_periph_clock_enable(usartx_rx_rcu); // 配置时钟
    gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
    gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
    //gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);

    /************** usart config **************/
    // 串口时钟
    rcu_periph_clock_enable(RCU_USART0);
    // USART复位
    usart_deinit(usartx);

    usart_baudrate_set(usartx, usartx_p_baudrate);	// 波特率
    usart_parity_config(usartx, usartx_p_parity); // 校验位
    usart_word_length_set(usartx, usartx_p_wl); // 数据位数
    usart_stop_bit_set(usartx, usartx_p_stop_bit); // 停止位
    usart_data_first_config(usartx, usartx_p_data_first); // 先发送高位还是低位

    // 发送功能配置
    usart_transmit_config(usartx, USART_TRANSMIT_ENABLE); 

    // 接收功能配置
    usart_receive_config(usartx, USART_RECEIVE_ENABLE);
    // 接收中断配置
    nvic_irq_enable(usartx_irqn, 2, 2);
    // usart int rbne
    usart_interrupt_enable(usartx, USART_INT_RBNE);
    usart_interrupt_enable(usartx, USART_INT_IDLE);

    // 使能串口
    usart_enable(usartx); 
}

//发送一byte数据
void send_byte(uint8_t data) {
    //通过USART发送
    usart_data_transmit(USART0, data);
    //判断缓冲区是否已经空了
    //FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

// 发送多个byte数据
void send_data(uint8_t* data, uint32_t len) {
    while(data && len--) {
        send_byte(*data);
        data++;
    }
}

//发送字符串
void send_string(char *data){
    //满足: 1.data指针不为空  2.发送的数据不是\0结束标记
    while(data && *data){
        send_byte((uint8_t)(*data));
        data++;
    }
}

//重写fputc方法  调用printf,会自动调用这个方法实现打印
int fputc(int ch, FILE *f){
    send_byte((uint8_t)ch);
    return ch;
}


void USART0_IRQHandler(void) {
    if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {
		usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
        uint16_t value = usart_data_receive(USART0);
        g_recv_buff[g_recv_length] = value;		
        g_recv_length++;
    }
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
        //读取缓冲区,清空缓冲区
        usart_data_receive(USART0);
        g_recv_buff[g_recv_length] = '\0';

        // TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度
        printf("%s", g_recv_buff);

        g_recv_length = 0;
    }
}


int main(void)
{
    systick_config();
    USART_config();

    while(1) {
    }
}
相关推荐
代码游侠3 小时前
ARM开发——阶段问题综述(二)
运维·arm开发·笔记·单片机·嵌入式硬件·学习
DLGXY3 小时前
STM32——旋转编码器计次(七)
stm32·单片机·嵌入式硬件
羽获飞4 小时前
从零开始学嵌入式之STM32——3.使用寄存器点亮一盏LED灯
单片机·嵌入式硬件
浩子智控5 小时前
商业航天计算机抗辐射设计
单片机·嵌入式硬件
独处东汉8 小时前
freertos开发空气检测仪之输入子系统结构体设计
数据结构·人工智能·stm32·单片机·嵌入式硬件·算法
czy87874759 小时前
机智云 MCU OTA可以对MCU程序进行无线远程升级。
单片机·嵌入式硬件
A9better11 小时前
嵌入式开发学习日志52——二值与计数信号量
单片机·嵌入式硬件·学习
_chirs12 小时前
编译不依赖动态库的FFMPEG(麒麟国防 V10)
arm开发·ffmpeg
日更嵌入式的打工仔12 小时前
(实用向)中断服务程序(ISR)的优化方向
笔记·单片机
想放学的刺客13 小时前
单片机嵌入式试题(第25)嵌入式系统可靠性设计与外设驱动异常处理
stm32·单片机·嵌入式硬件·mcu·物联网