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) {
    }
}
相关推荐
析木不会编程40 分钟前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉5 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6775 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式大圣5 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室6 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费6 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_397562318 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo20178 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
艺术家天选8 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件
向阳逐梦8 小时前
基于STM32F4单片机实现ROS机器人主板
stm32·单片机·机器人