三、串口中断

目录

1、通信分类

2、串口通信协议:

3、程序


1、通信分类

(1)按数据通信方式分类,可分为串行通信和并行通信两种。

        串行通信的基本特征是数据逐位顺序依次传输,优点是传输线少、布线成本低、灵活度高,一般用于近距离人机交互,特殊处理后也可以用于远距离,缺点是传输速率低。

        并行通信是数据各位可以通过多条线同时传输,优点是传输速率高,缺点就是布线成本高,抗干扰能力差因而适用于短距离、高速率的通信。

(2)根据数据传输方向,通信又可分为全双工、半双工和单工通信。

        单工是指数据传输仅能沿一个方向,不能实现反方向传输,如校园广播。

        半双工是指数据传输可以沿着两个方向,但是需要分时进行,共用一条线路实现双向通信,如对讲机。

        全双工是指数据可以同时进行双向传输,用两条线路,一条用于发送数据,另一条用于接收数据,日常的打电话属于这种情形。

(3)根据数据同步方式,通信又可分为同步通信和异步通信。

        同步通信要求通信双方共用同一时钟信号,在总线上保持统一的时序和周期完成信息传输。优点:可以实现高速率、大容量的数据传输,以及点对多点传输。缺点:要求发送时钟和接收时钟保持严格同步,收发双方时钟允许的误差较小,同时硬件复杂。

        异步通信不需要时钟信号,而是在数据信号中加入开始位和停止位等一些同步信号,以便使接收端能够正确地将每一个字符接收下来,某些通信中还需要双方约定传输速率。优点:没有时钟信号硬件简单,双方时钟可允许一定误差。缺点:通信速率较低,只适用点对点传输。

        简单区分同步和异步就是看通信时需不需要对外提供时钟输出。


2、串口通信协议:

(1)波特率

        波特率表示每秒钟传送的码元符号的个数,它决定了数据帧里面每一个位的时间长度。两个要通信的设备的波特率一定要设置相同。

(2)数据帧

        数据帧格式需要提前约定好,串口通信的数据帧包括起始位、停止位、有效数据位以及校验位。

        1. 起始位和停止位

        串口通信的一个数据帧是从起始位开始,直到停止位。数据帧中的起始位是由一个逻辑 0 的数据位表示,而数据帧的停止位可以是 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。

        2. 有效数据位

        数据帧的起始位之后,就接着是数据位,也称有效数据位,这就是我们真正需要的数据,有效数据位通常会被约定为 5、6、7 或者 8 个位长。有效数据位是低位(LSB)在前,高位(MSB)在后。

        3. 校验位

        校验位可以认为是一个特殊的数据位。校验位一般用来判断接收的数据位有无错误,检验方法有:奇检验、偶检验、0 检验、1 检验以及无检验

        奇校验要求帧数据和校验位中“1”的个数为奇数。比如一个 8 位长的有效数据为:10101001,总共有 4 个“1”,为达到奇校验效果,校验位设置为“1”,最后传输的数据是 8 位的有效数据加上 1 位的校验位总共 9 位。

        偶校验要求帧数据和校验位中“1”的个数为偶数。

        0 校验是校验位总为“0”。

        1 校验是校验位总为“1”。

        无校验是指数据帧中不包含校验位。


3、程序

 串口初始化

#define USART_REC_LEN 200    /* 定义最大接收字节数 200 */
#define USART_EN_RX 1        /* 使能(1)/禁止(0)串口 1 接收 */
#define RXBUFFERSIZE 1       /* 缓存大小 */


/**
* @brief 串口 X 初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* 这里的 USART 的时钟源在 sys_stm32_clock_init()函数中已经设置过了.
* @retval 无
*/
void usart_init(uint32_t baudrate)
{
    uartx_handle.Instance = USART1;         /* USART1 */
    uartx_handle.Init.BaudRate = baudrate;  /* 波特率 */
    uartx_handle.Init.WordLength = UART_WORDLENGTH_8B;     /* 字长为 8 位数据格式 */
    uartx_handle.Init.StopBits = UART_STOPBITS_1;          /* 一个停止位 */
    uartx_handle.Init.Parity = UART_PARITY_NONE;           /* 无奇偶校验位 */
    uartx_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;     /* 无硬件流控 */
    uartx_handle.Init.Mode = UART_MODE_TX_RX;              /* 收发模式 */
    HAL_UART_Init(&uartx_handle);           /* HAL_UART_Init()会使能 UART1 */
 
    /*该函数会开启接收中断:标志位 UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量*/
    HAL_UART_Receive_IT(&uartx_handle, (uint8_t *)aRxbuffer, RXBUFFERSIZE);
}

引脚初始化

/**
* @brief UART 底层初始化函数
* @param huart: UART 句柄类型指针
* @note 此函数会被 HAL_UART_Init()调用
* 完成时钟使能,引脚配置,中断配置
* @retval 无
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;

    if(huart->Instance == USART_UX) /* 如果是串口 1,进行串口 1 MSP 初始化 */
    {
        __HAL_RCC_USART1_CLK_ENABLE();   /* USART1 时钟使能 */
        __HAL_RCC_GPIOA_CLK_ENABLE();    /* 发送引脚时钟使能 */
        __HAL_RCC_GPIOA_CLK_ENABLE();    /* 接收引脚时钟使能 */

        gpio_init_struct.Pin = GPIO_PIN_9;         /* TX 引脚 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;   /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;       /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
        gpio_init_struct.Alternate = GPIO_AF7_USART1;     /* 复用为 USART1 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);          /* 初始化发送引脚 */

        gpio_init_struct.Pin = GPIO_PIN_10;          /* RX 引脚 */
        gpio_init_struct.Alternate = GPIO_AF7_USART1;/* 复用为 USART1 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);     /* 初始化接收引脚 */

        #if USART_EN_RX
            HAL_NVIC_EnableIRQ(USART1_IRQn);         /* 使能 USART1 中断通道 */
            HAL_NVIC_SetPriority(USART1_IRQn, 3, 3); /* 抢占优先级 3,子优先级 3 */
        #endif
    }
}

中断函数

/**
* @brief 串口 X 中断服务函数
 注意,读取 USARTx->SR 能避免莫名其妙的错误
* @param 无
* @retval 无
*/
void USART_UX_IRQHandler(void)
{
    #if SYSTEM_SUPPORT_OS /*使用 OS*/
        OSIntEnter();
    #endif

    HAL_UART_IRQHandler(&uartx_handler); /*调用 HAL 库中断处理公用函数*/
    while (HAL_UART_Receive_IT(&uartx_handler, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK) /*一次处理完成之后,重新开启中断并设置 RxXferCount 为 1*/
    {
        /* 如果出错会卡死在这里 */
    }

    #if SYSTEM_SUPPORT_OS /*使用 OS*/
        OSIntExit();
    #endif
}

串口回调函数

/**
* @brief UART 数据接收回调接口
 数据处理在这里进行
* @param huart:串口句柄
* @retval 无
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1) /* 如果是串口 1 */
    {
        if((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */
        {
            if(g_usart_rx_sta & 0x4000) /* 接收到了 0x0D(即回车键)*/
            {
                if(aRxBuffer[0] != 0x0A) /* 接收到的不是 0x0A(即不是换行键)*/
                {
                    g_usart_rx_sta = 0; /*接收错误,重新开始 */
                }
                else /* 接收到的是 0x0a(即换行键)*/
                {
                    g_usart_rx_sta |= 0x8000; /* 接收完成了 */
                }
            }
            else /* 还没收到 0x0D(即回车键) */
            {
                if (aRxBuffer[0] == 0x0D)
                    g_usart_rx_sta |= 0x4000;
                else
                {
                    g_usart_rx_buf[g_usart_rx_sta & 0x3FFF] = aRxBuffer[0];
                    g_usart_rx_sta++;

                    if (g_usart_rx_sta > (USART_REC_LEN - 1))
                    {
                        g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */
                    }
                }
            }
        }
    }
}

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无敌暴龙战士朵拉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值