06_串口通信

6.1 概述

6.2 串口设置

6.2.1 初始化

PA9 作为串口1 的输出
PA10 作为串口1的输入

void UART_Init(void){
    // 1.打开GPIOA/USART1控制器时钟 - APB2
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    // 2.配置PA9 - 推挽复用输出, 50MHz
    GPIO_InitTypeDef GPIO_Config;
    GPIO_Config.GPIO_Pin = GPIO_Pin_9;
    GPIO_Config.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Config.GPIO_Mode = GPIO_Mode_AF_PP; // 需要设置成 复用推挽输出 模式
    GPIO_Init(GPIOA, &GPIO_Config);
    
    // 3.配置PA10 - 浮空输入 
    GPIO_Config.GPIO_Pin = GPIO_Pin_10;
    GPIO_Config.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入 
    GPIO_Init(GPIOA, &GPIO_Config);
    
    // 4.配置工作参数: 115200 8n1 TX+RX 
    USART_InitTypeDef UART_Config; 
    UART_Config.USART_BaudRate = 115200;
    UART_Config.USART_WordLength = USART_WordLength_8b; 
    UART_Config.USART_Parity = USART_Parity_No; 
    UART_Config.USART_StopBits = USART_StopBits_1;
    UART_Config.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
    UART_Config.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1, &UART_Config);
    
    // 5.使能串口1
    USART_Cmd(USART1, ENABLE);
}

6.2.2 串口输出

// 发送一个字符
void UART_Putc(char c){
    
    // 循环的判断
    // TC, SET, 可以发送; RESET, 不能发送 
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    
    // 将字符c放入到串口1的DR中 
    USART_SendData(USART1, c);
}

// 发送一个字符串
// char* pstr = "hello";
void UART_Puts(char* pstr){
    while(*pstr){
        UART_Putc(*pstr);
        pstr++;
    }
}

6.2.3 串口输入

// 获取一个字符
char UART_Getc(void)
{
    // RXNE
    // RESET, DR没有数据, 陷入循环; SET, 有数据, 跳出循环
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    
    // 从串口1中获取一个字符
    return (char)USART_ReceiveData(USART1);
}
// char buf[len];
// 上位机 - "xxxx\r\n" -> "xxxx"
// "hello\r\n" -> "hello\0\n" -> "hello"
// 对接收的字符串做了 调整
void UART_Gets(char* buf, u32 len)
{
    int i = 0; 
    for( i = 0; i < (len-1); i++) {
        buf[i] = UART_Getc();
        if (buf[i] == '\n')
            break;
    }
    buf[i-1] = '\0';
}

 

6.3 串口使用中断

6.3.1 在uart初始化中设置中断

void UART_Init(void){
    // 1.打开GPIOA/USART1控制器时钟 - APB2
    // 2.配置PA9 - 推挽复用输出, 50MHz
    // 3.配置PA10 - 浮空输入 
    // 4.配置工作参数: 115200 8n1 TX+RX 
    // 5.使能串口1
    // .......

    // 6.配置NVIC支持串口1的中断
    NVIC_InitTypeDef NVIC_Config;
    NVIC_Config.NVIC_IRQChannel = USART1_IRQn;// 串口1的中断通道
    NVIC_Config.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_Config.NVIC_IRQChannelSubPriority = 2;
    NVIC_Config.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_Config);
    
    // 7.配置USART1控制器支持RXNE中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    // 外设数据-> 串口1的DR 
    // 串口1 -> RXNE中断 -> NVIC -> CPU核 -> 中断处理函数 
    // 触发了多次中断 -> 多次调用中断处理函数 
}

6.3.2 串口中断处理函数

一般我们对串口接收 设置中断, 中断到达后, 设置flag. 然后在main中检查 该flag, 

// 定义串口1接收数组长度 
#define  UART_RXBUFF_SIZE     1024

// 声明串口1的接收数组 
char UART_RxBuff[UART_RXBUFF_SIZE];

// 用于计数 / 下标 
int UART_RxCounter = 0; 

// 声明变量表示数据是否读取结束 
// 0,数据正在读取; 1,数据读取完毕;
int UART_Send_Flag = 0; 

// 串口1的中断处理函数
// "led on\r\n"
//  0123456 7   
//            ^-counter
void USART1_IRQHandler(void) {
    char c;
    // 判断是否是RXNE中断 
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        // 清除中断到来位 
        USART_ClearITPendingBit(USART1, USART_IT_RXNE); 
        // 从DR寄存器中读取数据
        c = USART_ReceiveData(USART1); 
        UART_RxBuff[UART_RxCounter++] = c;
        if ('\n' == c) { // 读取结束
            UART_RxBuff[UART_RxCounter-2] = '\0';
            // 将UART_RxCounter清0
            UART_RxCounter = 0;
            // 数据读取结束
            UART_Send_Flag = 1;
        }
    }
}

 

posted @ 2025-05-13 20:37  靖意风  Views(17)  Comments(0)    收藏  举报