USART

设置时钟:
RCC_APB2Periph_AFIO 功能复用 IO 时钟
RCC_APB2Periph_GPIOA GPIOA 时钟
RCC_APB2Periph_USART1 USART1 时钟
你可以用
//使能串口1,PA,AFIO总线
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_USART1 ,ENABLE);
或直接
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL,ENABLE); //全部 APB2 外设时钟开启
注意 USART2 的你开启为 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
设置 GPIO:
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; //推挽输出-TX
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入-RX
GPIO_Init(GPIOA, &GPIO_InitStructure);
设置 USART:
这里我用的是 3.0 的库相对于 2.0 的库来说多了一步,先说 2.0USART_InitTypeDef USART_InitStructure;
USART_StructInit(&USART_InitStructure); //装填默认值
USART_Init(USART1, &USART_InitStructure); //根据 USART_InitStruct 中指定的参数初始化外设 USARTx
寄存器
USART_Cmd(USART1, ENABLE); //启用
就好了~!
而 3.0 的库需要
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_StructInit(&USART_InitStructure);
USART_ClockStructInit (&USART_ClockInitStructure);
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
// 只 是多 分出 了 1 个 USART_ClockInitStructure 我 也不 知为 啥 要这 样? ? 为了 同步 异 步模 式?
USART_InitStruct 中指定的参数内容为:(2.0 的)
typedef struct
{
u32 USART_BaudRate; //USART 传输的波特率
u16 USART_WordLength; //一个帧中传输或者接收到的数据位数通常是 8
u16 USART_StopBits; //停止位
u16 USART_Parity; //奇偶校验
u16 USART_HardwareFlowControl; //硬件流控制模式使能还是失能
u16 USART_Mode; //指定了使能或者失能发送和接收模式
u16 USART_Clock; //提示了 USART 时钟使能还是失能
u16 USART_CPOL; //指定了下 SLCK 引脚上时钟输出的极性
u16 USART_CPHA; //指定了下 SLCK 引脚上时钟输出的相位
u16 USART_LastBit;
//来控制是否在同步模式下,在 SCLK 引脚上输出最后发送的那个数据字通常用 USART_LastBit_Disable
} USART_InitTypeDef;我靠~!太细了~!我只知道(9600,8,n,1)这就够了 其他的统统默认~!
USART_StructInit(&USART_InitStructure);
USART_ClockStructInit (&USART_ClockInitStructure); //2.0 不用这句,这样就设好了好了~!自动为
您装填了默认参数。默认的参数如下(3.0 的库):
void USART_StructInit(USART_InitTypeDef* USART_InitStruct)
{
USART_InitStruct->USART_BaudRate = 9600;
USART_InitStruct->USART_WordLength = USART_WordLength_8b;
USART_InitStruct->USART_StopBits = USART_StopBits_1;
USART_InitStruct->USART_Parity = USART_Parity_No ;
USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None;
}
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct)
{
USART_ClockInitStruct->USART_Clock = USART_Clock_Disable;
USART_ClockInitStruct->USART_CPOL = USART_CPOL_Low;
USART_ClockInitStruct->USART_CPHA = USART_CPHA_1Edge;
USART_ClockInitStruct->USART_LastBit = USART_LastBit_Disable;
}
/*******************************************************************************************
*****/
当然了你也可以自己设参数,比如这样。
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;USART_InitStructure.USART_BaudRate = 9600;
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_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Cmd(USART1, ENABLE);
} USART_ClockInitStructure.USART_CPHA= USART_CPHA_2Edge;除了这句以外其他的都和默认的参数
一样,二者有啥区别我至今也不太清楚但就一般的应用来说两个都可以正常工作。
收发的方法:
1.发送
void USART1_Puts(char * str)
{
while(*str)
{
USART_SendData(USART1, *str++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}USART1_Puts("hello-java~!\r\n"); //这样就发送了 hello-java~!
跟 C 语言的 printf 不太一样在于\n 并没有另起一行要用个\r 这样在终端上好看。
2.接收
u8 uart1_get_data; //存放接受的内容
while(1)
{
if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET)
{
uart1_get_data = USART_ReceiveData(USART1);
USART1_Puts("\r\n 获取到串口 1 数据:");
USART1_Putc(uart1_get_data);
USART1_Puts("\r\n");
}
}
STM32 串口通信的三种方式查询、中断、DMA
在 STM32 处理器中,将发送数据写入 USART_DR 寄存器,此动作清除 TXE(发送允许位)。软件读 RXNE 位完
成对 RXNE(接收寄存器非空位)清零。RXNE 必须在下一个字符接收结束前清零。
USART 的所有中断事件被连接到一个中断向量中,也就是说需要在中断例程中判别各种可能出现的情况。
数据寄存器实际上由两个寄存器组成,一个给发送用(TDR 只写),一个给接收用(RDR 只读)。和 AVR 的类
似,两个寄存器合并成一个 UDR 寄存器。
采用中断方式进行串口通信
通过对 CodeVersion AVR 上的串口通信程序的移植,在 STM32 上实现了串口数据收发的中断通信。收发各
自使用两个循环队列实现文件缓冲,从而提高了执行效率。
队列:一种先进先出(FIFO:First In First Out)的策略。
在向 USART 写数据时,先检测接收数据寄存器是否“满” ,如有数据则写入队列中。当每发送完一帧数据
后进入中断程序,检测队列中是否有数据,如有数据则发送,否则退出。USART 数据时的情况类似。
需要注意的是在 USART_putchar() 和 USART_getchar() 函数对缓冲区队列指针操作时需要禁止中断。
www.ec66.com 帝国提示,这种为查询方式通信。
Tips:在串口通讯中调用函数 USART_GetITStatus(USART1, USART_IT_TC)检测接收是否完成,
函数 USART_ClearFlag(USART1,USART_FLAG_TC)清除完成 中断标志位,它们 操作的都是同一 寄存器 位
USART_CR->TC(状态寄存器中的完成标志位)。
在其它中断中的 USRAT_FLAG_xx(标志位)和 USART_TI_xx(中断标志位)都表示同一个位。只是为了强调
其在特定函数中的作用,而采用不同表述方式。
但 USART_ITConfig(USART1, USART_IT_TC, DISABLE)函数中的 USART_IT_TC 位则是相应的中断允许位,实
际是对寄存器 USART_CR1->TCIE 位操作。
采用 DMA 方式进行串口通信
STM32 串口通信模块支持使用 DMA 方式进行数据传输,以下代码实现了数据 DMA 发送方式。当发送完毕产
生中断。
程序首先在 SRAM 中开辟大小为 BufferSize 的缓冲区 SRC_Char_Buffer[],在 main()函数中对其进行初始
化。DMA 初始化后 SRC_Char_Buffer 为源地址,USART1_DR_Base(USART1 数据寄存器)为目的地址。通过
USART_DMACmd()函数设置 USART_CR3 中的 DMAT(允许 DMA 发送位)。执行 DMA_Cmd()函数后使能 DMA 通道 4
传输,开始向串口数据寄存器发送数据。每发送一个字节源地址自动加 1,总共发送 BufferSize 个字节。
这一过程由 DMA 控制器完成,无须 CPU 参与。发送完成后进入中断,中断服务程序 CurrDataCounter 的值
并 通 过 软件 设 置 清 除 通 道 全局 标 志 ( 同 时 发送 完 成 标 志 TC 自 动 得 到清 除 )。 主 程 序通 过 判 断
CurrDataCounter 的值是否为零,决定 DMA 传输是否结束。为“0”则表示成功,打印相应信息。在实际使
用中,CPU 可以在数据发送同时执行其它操作。
STM32 的 UART 的 GPIO 管脚配置的异常问题
STM32 的 UART 的 GPIO 管脚配置
参照 STM32 的数据手册,其 GPIO 管脚具有 8 种输入输出模式:
1. 浮空输入
2. 带上拉输入
3. 带下拉输入
4. 模拟输入
5. 开漏输出
6. 推挽输出
7. 复用功能的推挽输出
8. 复用功能的开漏输出
根据具体情况进行灵活配置。
我在使用 UART 的时候就出现过配置错误的情况,我把 RX 管脚配置成 input floating,外部没有接上拉电
阻,后面接了 485 电平转换芯片 SN65HDV10,结果本应该只接收 1 个字节,但一直接收到 0x00,原因是 485
芯片设置成发送状态后其接收管脚为高阻态,而 STM32 芯片为悬空态,实际测试该管脚为低电平,所以一
直接收到 0x00,将 STM32 的 UART 接收管脚配置为 input pull-up 后正常接收。
STM32 中断法 USART 串口简单使用
下面介绍中断法。
首先配置时钟:这里我拿 USART2 说事:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //USART2 和 USART3 都在在 APB1 上而 USART1
是在 APB2 上的
设置 GPIO:
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO |ENABLE);
// A2 做 T2X
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// A3 做 R2X
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
配置 SUART2:
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_StructInit(&USART_InitStructure);
USART_ClockStructInit (&USART_ClockInitStructure);
USART_ClockInit(USART2, &USART_ClockInitStructure);
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); //开启 SUART2 的接收中断同理还有【看图】
然后中断服务程序:这个自己在 stm32f10x_it.c 添加就可以了。
void USART2_IRQHandler(void)
{
//接收中断
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET){
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
Uart2_Get_Data=USART_ReceiveData(USART2);
Uart2_Get_Flag=1;
}
//溢出-如果发生溢出需要先读 SR,再读 DR 寄存器则可清除不断入中断的问题[牛人说要这样]
if(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET)
{
USART_ClearFlag(USART2,USART_FLAG_ORE); //读 SR 其实就是清除标志
USART_ReceiveData(USART2); //读 DR
}
}
然后在 main 里检测 Uart2_Get_Flag
if(Uart2_Get_Flag)
{
Uart2_Get_Flag=0;
USART2_Puts("\r\n 2 获取到串口 2 数据:");
USART2_Putc(Uart2_Get_Data);
USART2_Puts("\r\n");
}
写法就比较灵活了其实中断实在是强大
03-09
### 关于USART(通用同步异步收发传输器) #### USART简介 USART代表Universal Synchronous Asynchronous Receiver Transmitter,即通用同步异步收发器[^1]。这种设备能够处理两种类型的通信模式——同步和异步,在嵌入式系统设计中广泛用于微控制器与其他外围设备之间的串行数据交换。 #### 编程步骤概述 为了有效利用USART功能,开发者通常遵循一系列标准化的配置流程: - 使能RX和TX引脚GPIO时钟以及USART本身所需的时钟资源; - 对指定的GPIO端口进行初始化设置,并将其映射至对应的USART线路; - 设置波特率、字长、停止位等基本参数以适应特定应用环境的需求; - 如果计划采用中断驱动的方式,则需进一步调整NVIC优先级分配并向量表项关联; - 启用USART模块及其接收能力; - 实现ISR (Interrupt Service Routine),以便及时响应外部输入信号变化并执行相应操作逻辑[^3]。 #### 示例代码展示 下面给出一段基于STM32平台下的简单USART初始化与IrDA模式切换的例子: ```c // 配置USART2进入低功耗IrDA状态 void Configure_USART2_IrDALowPower(void){ // 假定在此之前已完成必要的硬件准备动作... /* 开启USART2 IrDA低功耗选项 */ USART_IrDAConfig(USART2, USART_IrDAMode_LowPower); } int main(){ // ...其他初始化工作... // 调用上述定义的方法完成特殊模式设定 Configure_USART2_IrDALowPower(); while(1){ // 主循环体内容... } } ``` 此片段展示了如何通过调用`USART_IrDAConfig()`函数来改变USART的工作方式为IrDA协议下的节能版本[^2]。 #### 注意事项 值得注意的是,尽管USART提供了灵活多样的通讯手段,但在实际部署过程中也存在一些局限性,比如相对较低的数据吞吐能力和较短的有效覆盖范围等问题[^4]。因此,在规划项目架构之初就应充分考虑到这些因素的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值