为了能到远方,脚下的每一步都不能少.|

京多安

园龄:1年3个月粉丝:2关注:1

2023-11-28 22:12阅读: 958评论: 0推荐: 0

STM32使用串口发送接收数据

前言

  串口通信一般用作异步通信,使用两根数据线进行收发:TX 和 RX,为利用USART 实现开发板与电脑通信,需要用到一个USB 转USART 的 IC,我们选择 CH340G 芯片来实现这个功能。本次实验采用串口1即usart1进行试验,将CH340G的TX连接单片机PA10,RX连接PA9,两块芯片共地,并且采用3.3V供电。

        image

接下来就是代码实现部分:

1.打开外设时钟

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟

2.对串口的端口进行配置

//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1

对于这个函数复用映射理解如下:
stm32f4的所有外设没有默认引脚,当使用外设时必须要使用GPIO_PinAFConfig函数选择引脚进行端口复用。也可以理解为stm32f4没有重映射,就是选择对应的端口进行端口复用。

相比之下stm32f1的外部中断与其他外设的端口复用都要用AFIO(即端口重映射)
如果不使用重映射,端口复用直接使用第一端口的话(外部中断除外),不需要使用AFIO。
对于f1来说查阅数据手册,复用直接使用第一端口,并且串口接收中断是内部中断,所以不需要使用AFIO
image

再对PA9和PA10进行初始化

//USART1端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10

本来PA10要设置为浮空输入模式,但是对于stm32f4来说
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;这种模式已经不存在,在F4的库里边只有这个模式:GPIO_Mode_AF。所有使用复用功能的引脚都应设置成这种模式。这样比F1方便多了。你不用考虑这个引脚应该设置成浮空输入还是推挽输出,因为引脚设置错误基本可以消失。

在STM32F1里边,这样方式配置时钟复用
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1,ENABLE);
打开复用时,但是在F4里边这个就不管用了。库里边根本就没有了这个变量RCC_APB2Periph_AFIO
总结原因:F4没有了时钟复用功能。配置完成之后,需要用GPIO_PinAFConfig()设置功能映射。非常方便

3.对串口外设进行初始化

//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
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_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1

对于串口发送来说,此时已经配置完成。串口数据接收有两种方式:查询和中断,查询使用函数,主函数不断检测是否接收标志位,不方便
if(USART_GetFlagStatus(USART1,USART_FLAG_RXE)== SET);

串口数据中断接收需要进行额外的配置,每接收一个数据会产生相应的内部中断,所以需要配置NVIC
代码如下:

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器

4.串口数据发送

/***********************************************************/
//发送一个字节
void Sendbyte(uint8_t Byte)
{
USART_SendData(USART1, Byte); //调用发送数据函数
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//等待发送完成
}
//调用
Sendbyte('A');//发送一个字节
/***********************************************************/
/***********************************************************/
//发送一个数组
void SendArray(uint8_t *Array,uint16_t Length) //数组无法判断是否结束,所以再传递Length
{
uint16_t i;
for(i=0; i<Length ; i++)
{
Sendbyte(Array[i]);
}
}
//发送数组,也就是连续发送多个字节
uint8_t MyArray[] = {0x40,0x41,0x42,0x43,0x44};
SendArray(MyArray,5);
/***********************************************************/
/***********************************************************/
//发送字符串
void SendString(char *String)//字符串自带结束标志位,无需再传递参数
{
uint16_t i;
for(i=0; String[i] != '\0'; i++) //'\0'也可直接写0,结束标志位
{
Sendbyte(String[i]);
}
}
//调用
SendString("HelloWorld\r\n");
/***********************************************************/
/***********************************************************/
//使用打印函数
#include "stdio.h"
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
//主函数调用,这种方法只能在一个串口使用,比如此时用的串口1
printf("Num = %d\r\n",666);
//别的串口要使用打印,可以选sprintf,该函数可以指定打印位置
char String[100];
sprintf(String,"Num = %d\r\n",666);
SendString(String);
/***********************************************************/

5.串口数据接收

前面已经配置好了相关中断,接下来只需要在中断服务函数里面写代码

void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收中断,每接收一个数据产生一个中断
{
Res =USART_ReceiveData(USART1);//(USART1->DR);//读取接收到的数据
Sendbyte(Res); //将接收到的数据再发出去
}
}

本文作者:京多安

本文链接:https://www.cnblogs.com/manchestercity/p/17863250.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   京多安  阅读(958)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起