Stm32学习笔记二————通过USART1收发数据

不忍一时之苦,何谈百世之功

1、USART简介

    通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式
的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。

    STM32 的串口资源相当丰富的,功能也相当强劲。比如STM32F103ZET6 最多可提供 5 路串
口,有分数波特率发生器,支持同步单向通信和半双工单线通信,支持LIN(局部互连网),智能卡
协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理
器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。

2、USART功能概述

    接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚:接收数据
输入(RX)和发送数据输出(TX)。

    RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
    TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,
并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送
和接收。

    串口外设主要由三个部分组成,分别是波特率的控制部分、收发控制部分及数据存储转移部分。

  1、波特率控制
   波特率,即每秒传输的二进制位数,用 b/s (bps)表示,通过对时钟的控制可以改变波特率。
在配置波特率时,我们向波特比率寄存器 USART_BRR 写入参数,修改了串口时钟的分频值 
USARTDIV。USART_BRR 寄存器包括两部分,分别是 DIV_Mantissa(USARTDIV 的整数部分)和
DIVFraction(USARTDIV的小数)部分,最终,计算公式为:
			USARTDIV=DIV_Mantissa+(DIVFraction/16)。

  2、分数波特率的产生
    接收器和发送器的波特率在USARTDIV的整数和小数寄存器中的值应设置成相同。
		    Tx / Rx 波特率 =fCK/(16*USARTDIV)

  这里的fCK是给外设的时钟(PCLK1用于USART2、3、4、5,PCLK2用于USART1) USARTDIV是
一个无符号的定点数。这12位的值设置在USART_BRR寄存器。
    注: 在写入USART_BRR之后,波特率计数器会被波特率寄存器的新值替换。因此,不要在通信
进行中改变波特率寄存器的数值。
    USARTDIV 是对串口外设的时钟源进行分频的,对于 USART1,由于它是挂载在 APB2 总线上	
的,所以它的时钟源为 fPCLK2;而 USART2、3 挂载在APB1 上,时钟源则为 fPCLK1,串口的
时钟源经过 USARTDIV 分频后分别输出作为发送器时钟及接收器时钟,控制发送和接收的时序。 

    3、收发控制
    围绕着发送器和接收器控制部分,有好多个寄存器:CR1、CR2、CR3、SR,即 USART 的
三个控制寄存器(Control Register)及一个状态寄存器(Status Register)。通过向寄存器
写入各种控制参数,来控制发送和接收,如奇偶校验位,停止位等,还包括对 USART 中断的
控制;串口的状态在任何时候都可以从状态寄存器中查询得到。具体的控制和状态检查,我们
都是使用库函数来实现的,在此就不具体分析这些寄存器位了。

    4、数据存储转移部分
  收发控制器根据我们的寄存器配置,对数据存储转移部分的移位寄存器进行控制。
    当我们需要发送数据时,内核或 DMA 外设(一种数据传输方式,在下一章介绍)把数据从内存
(变量)写入到发送数据寄存器 TDR 后,发送控制器将适时地自动把数据从 TDR 加载到发送移位寄
存器,然后通过串口线 Tx,把数据一位一位地发送出去,在数据从 TDR 转移到移位寄存器时,会
产生发送寄存器TDR 已空事件 TXE,当数据从移位寄存器全部发送出去时,会产生数据发送完成事
件 TC,这些事件可以在状态寄存器中查询到。
  而接收数据则是一个逆过程,数据从串口线 Rx 一位一位地输入到接收移位寄存器,然后自动
地转移到接收数据寄存器 RDR,最后用内核指令或 DMA读取到内存(变量)中。

3、创建工程项目,勾选相应的固件库

       选中:CMSIS>CORE;Device>Startup;>StdPeriphDrivers>Flash;>Framework;>GPIO;
   >RCC;>USART等.

4、串口设置的一般步骤可以总结为如下几个步骤:

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

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);

2)串口复位;

    当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让
其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是
在函数 USART_DeInit()中完成:
    void USART_DeInit(USART_TypeDef* USARTx);//串口复位
比如要复位串口 1,方法为:
    USART_DeInit(USART1); //复位串口 1

3) GPIO端口模式设置;

	//PA9
        //声明结构体  
	GPIO_InitTypeDef GPIO_InitStructure; 
        //设置选择引脚 
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; 
	//设置引脚最大输出频率
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; 
	//设置引脚输出模式——复用推挽输出
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; 
	//根据设置的InitStructure初始化GPIO口
        GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//PA10
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; 
	//设置引脚输出模式——浮空输入
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; 
	//根据设置的InitStructure初始化GPIO口
        GPIO_Init(GPIOA,&GPIO_InitStructure);

4)串口参数初始化;

USART_InitTypeDef USART_InitStructure; 
USART_InitStructure.USART_BaudRate = Baudrate; //设置波特率     
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
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_Tx | USART_Mode_Rx;  //收发模式
USART_Init(USART1,&USART_InitStructure); //初始化串口1

5)开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init (&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启串口接受完成中断
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启串口空闲中断

6)使能串口;

USART_Cmd(USART1,ENABLE); //使能串口1

7)编写中断处理函数;

void USART1_IRQHandler(void)
{
  if((USART_GetITStatus(USART1,USART_IT_RXNE))!=RESET) //判断是否有中断
  {
    aRxbuffer[counter++] = USART_ReceiveData(USART1); //接收字符存入数组
    USART_ClearFlag(USART1,USART_IT_RXNE);	//清除中断标志位
  }
  else if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET)
  {
    USART1->SR;
    USART1->DR;
    counter = 0;
    if(memcmp((uint8_t*)aRxbuffer,(uint8_t *)aRxbuffCompare,BUFFERSIZE)==0)
    {
      Usart_SendString(USART1,(char *)aTxbuffer);
    }
    else
    {
      Usart_SendString(USART1,"Error");//(char *)aRxbuffer
    }
}
USART_ClearFlag(USART1,USART_IT_RXNE);	//清除中断标志位
}

5、参考链接

  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于HAL库的STM32 USART3中断收发数据代码示例: ```c #include "stm32f4xx_hal.h" USART_HandleTypeDef huart3; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART3_UART_Init(void); uint8_t rx_buffer[10]; // 接收缓冲区 uint8_t tx_buffer[] = "Hello, world!"; // 发送缓冲区 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART3_UART_Init(); while (1) { HAL_UART_Transmit_IT(&huart3, tx_buffer, strlen(tx_buffer)); // 发送数据 HAL_Delay(1000); // 延时 1s } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART3) { // 处理接收到的数据 // ... HAL_UART_Receive_IT(&huart3, rx_buffer, 1); // 继续接收数据 } } void MX_USART3_UART_Init(void) { huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_8B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_NONE; huart3.Init.Mode = UART_MODE_TX_RX; huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart3.Init.OverSampling = UART_OVERSAMPLING_16; huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart3) != HAL_OK) { Error_Handler(); } HAL_UART_Receive_IT(&huart3, rx_buffer, 1); // 开始接收数据 } void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 84; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } ``` 在上述代码中,我们使用了 HAL 库提供的 `HAL_UART_Transmit_IT` 和 `HAL_UART_Receive_IT` 函数来进行数据的发送和接收。在程序启动时,我们开启了 USART3 的中断接收,并在 `HAL_UART_RxCpltCallback` 中处理接收到的数据。如果有需要,可以根据实际情况对代码进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值