STM32F1笔记(三)UART/USART

UART:Universal Asynchronous Receiver/Transmitter(通用异步收/发器)

USART:Universal Synchronous/Asynchronous Receiver/Transmitter(通用同步/异步串行收/发器)

从命名即可看出USART就是UART的基础上添加了同步功能。通常把UART/USART称为串口。

串口包含TLL电平和232的串口,485等电气特性的串口。232、485通常应用于工业。

串口配置的一般步骤可以参考正点原子的总结:

1、串口时钟使能,GPIO时钟使能;

2、串口复位;(我不知道这一步的意义,去掉似乎也没影响,求大神指点)

3、GPIO端口模式的配置;

4、串口参数初始化;

5、初始化NVIC并开启中断;

6、使能串口;

7、编写中断服务函数。

配置示例:

void Usart3_Init(unsigned int BaudRate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    
    USART_DeInit(USART3);
  
    //USART3_TX   GPIOB.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
   
    //USART3_RX	  GPIOB.11
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  
    USART_InitStructure.USART_BaudRate = BaudRate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_Init(USART3, &USART_InitStructure);
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
    USART_Cmd(USART3, ENABLE);
}

注意:在此示例中GPIO的速率配置为50M,其实没必要那么高,可降低至2M。速率越高,噪声越大,功耗越高。

在配置代码中,开启了接收中断。在日常串口使用中,都会规定通信协议。通信协议的解析,通常在中断服务函数里进行。

通信协议通常由帧头,数据,帧尾三部分组成。

帧头不正确,不继续处理后续接收到的内容。

帧尾不正确,对数据不进行处理。

示例:

帧头由两部分组成,校验信息和数据长度。示例中断校验信息,赋值给unsigned char的变量,相加后为0。这是特殊的帧头。

    unsigned char chr = 0;

    chr += (0xAA + 0xBB + 0xCC + 0xDD + 0xEE + 0x04);

    printf("chr=%X\n", chr);

数据长度通常只指数据的长度,不包含帧头校验信息和帧尾的长度。

帧尾可以是CRC等校验方式。可包含长度也可不包含,计算数据的CRC。目的是确保数据的一致性。

串口中断服务函数示例:

void USART3_IRQHandler(void)
{       
    if(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == SET)
    {
        USART_ClearITPendingBit(USART3, USART_IT_RXNE);
        
        g_usart3_recv_data = USART_ReceiveData(USART3);
        
        switch(g_usart3_recv_state)
        {
            case USART3_RECV_FIRST_FRAME_HEAD:
                if(MKLM_FIRST_FRAME_HEAD == g_usart3_recv_data)
                {
                    g_usart3_recv_state = USART3_RECV_SECOND_FRAME_HEAD;   
                }
                else
                {
                    g_usart3_recv_state = USART3_RECV_FIRST_FRAME_HEAD;             
                }
                break;
            
            case USART3_RECV_SECOND_FRAME_HEAD:
                if(MKLM_SECOND_FRAME_HEAD == g_usart3_recv_data)
                {
                    g_usart3_recv_state = USART3_RECV_FIRST_LENGTH;
                }
                else
                {
                    g_usart3_recv_state = USART3_RECV_FIRST_FRAME_HEAD;             
                }
                break;
                
            case USART3_RECV_FIRST_LENGTH:
                g_Usart3_recv_struct.length = g_usart3_recv_data;
                g_Usart3_recv_struct.length <<= 8;
                g_usart3_recv_state = USART3_RECV_SECOND_LENGTH; 
                break;
            
            case USART3_RECV_SECOND_LENGTH:
                g_Usart3_recv_struct.length |= g_usart3_recv_data;
                g_usart3_recv_length = 0;
                g_usart3_recv_state = USART3_RECV_ADDRESS; 
                break;
            
            case USART3_RECV_ADDRESS:
                g_Usart3_recv_struct.address = g_usart3_recv_data;
                g_usart3_recv_length++;
                g_usart3_recv_state = USART3_RECV_ORDER;
                break;
            
            case USART3_RECV_ORDER:
                g_Usart3_recv_struct.order = g_usart3_recv_data;
                g_usart3_recv_length++;
                g_usart3_recv_state = USART3_RECV_ACTION; 
                break;
            
            case USART3_RECV_ACTION:
                g_Usart3_recv_struct.action = g_usart3_recv_data;
                g_usart3_recv_length++;
                g_usart3_recv_state = USART3_RECV_FIRST_CRC;
                break;
            
            case USART3_RECV_FIRST_CRC:
                g_Usart3_recv_struct.crc16 = g_usart3_recv_data;
                g_Usart3_recv_struct.crc16 <<= 8;
                g_usart3_recv_length++;
                g_usart3_recv_state = USART3_RECV_SECOND_CRC;
                break;
            
            case USART3_RECV_SECOND_CRC:
                g_Usart3_recv_struct.crc16 |= g_usart3_recv_data;
                g_usart3_recv_length++;
            
                if(g_usart3_recv_length == g_Usart3_recv_struct.length)
                {
                    g_recv_status = RECEIVE_OK;
                }
                else 
                {
                    g_recv_status = RECEIVE_LENGTH_ERROR;
                }
                                    
                g_usart3_recv_flag = USART3_RECV_SECCESS;
                g_usart3_recv_length = 0;
                g_usart3_recv_state = USART3_RECV_FIRST_FRAME_HEAD;
                break;
            
            default:
                break;
        }
    }
}

STM32使用printf的方法。

在魔术棒里勾选Use MicroLIB(默认是不勾选的)

如果不勾选会出现在BEAB BKPT 0xAB 死循环,如下图

 

以串口2为例,在串口2相关.c里(可在任何位置,为防混乱放在需要配置给printf的串口文件里)

加入以下代码(别忘了添加包含头文件stdio.h)

#include <stdio.h>

int fputc(int ch, FILE* stream)
{
    while (!(USART2->SR & USART_FLAG_TXE));
    USART_SendData(USART2, (uint8_t)ch);
    
    return ch;
}

就可以调用printf了,调用前别忘了相关串口要初始化。

Uart2_Init(9600); 
     
while(1)
{
    printf("Hello World!\r\n");
    delay_ms(100);
}

通过串口助手可以看到现象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dr_Haven

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

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

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

打赏作者

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

抵扣说明:

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

余额充值