STM32F103 使用寄存器方式配置和使用串口(USART)进行数据的发送和接收是一个相对底层且直接的操作。
以下是我例的一个简化的步骤,用于配置 STM32F103 的 USART进行基本的发送和接收操作:
1. 初始化 GPIOUSART2 通常使用 PA9 (TX) 和 PA10 (RX) 作为其引脚。你需要配置这两个引脚为复用推挽输出(对于 TX)和浮空输入(对于 RX)。2. 初始化 USART设置 USART 的波特率、数据位、停止位和校验位。使能 USART 的接收和发送中断(如果需要中断驱动)。使能 USART。3. 发送数据将数据写入 USART 的数据寄存器(USART->DR)。等待发送完成(可以通过查询标志位或中断来实现)。4. 接收数据读取 USART 的数据寄存器(USART->DR)来获取接收到的数据。清除相关的接收标志位。在中断服务例程中处理接收到的数据。这里只给出一些关键的代码片段,而不是完整的初始化函数或中断服务例程。
还是把原理图弄过来,方便分析:

主核心代码:

串口初始化:


还是把代码帖上来:
void My_USART1(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART1_InitStrue;
NVIC_InitTypeDef NVIC_InitStructure;
//1、串口时钟、GPIOA时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
//2、GPIOA端口模式设置
GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_TX;//PA9
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_RX;//PA10
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//3、串口参数初始化
USART1_InitStrue.USART_BaudRate = 9600;
USART1_InitStrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART1_InitStrue.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
USART1_InitStrue.USART_Parity = USART_Parity_No;
USART1_InitStrue.USART_StopBits=USART_StopBits_1;
USART1_InitStrue.USART_WordLength = USART_WordLength_8b;
USART_Init( USART1, &USART1_InitStrue);
//4、开启中断并且初始化NVIC
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel =USART1_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
//5、使能串口
USART_Cmd(USART1,ENABLE);
//6、编写中断处理函数
}
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
/* Transmit Data */
USARTx->DR = (Data & (uint16_t)0x01FF);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}
void USART_SendString( USART_TypeDef * USARTx, char *str)
{
while(*str!='\0')
{
USART_SendByte( USARTx, *str++ );
}
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
}
uint8_t USART_ReceiveByte(USART_TypeDef* USARTx)
{
while(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)==RESET);
return (uint8_t)USART_ReceiveData(USART1);
}
void USART1_IRQHandler()
{
u16 temp;
// while(USART_GetITStatus(USART1,USART_IT_RXNE) == RESET);
if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
{
temp = USART_ReceiveData(USART1);
}
USART_SendByte(USART1,temp);
}
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
_sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
int main(void)
{
char i;
LED_GPIO_Config();
delay_init();
//KEY_GPIO_Config();
//TIM2_Init(4999,7199);
My_USART1();
USART_SendString(USART1, "电子产品世界");
while(1)
{
};
}解释一下函数的意思:
My_USART1(void)这个函数用于初始化USART1。时钟使能:首先,它使能了USART1和GPIOA的时钟,因为USART1的TX和RX引脚通常连接到GPIOA。GPIO初始化:然后,它设置了GPIOA的引脚模式,将TX引脚设置为复用推挽输出,RX引脚设置为浮空输入。USART初始化:接着,它配置了USART1的参数,如波特率、硬件流控制、工作模式、校验位、停止位和数据位。中断和NVIC配置:它启用了USART1的接收中断,并配置了NVIC(嵌套向量中断控制器)以处理该中断。使能串口:最后,它使能了USART1。USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)这个函数用于发送一个字节的数据。参数检查:它首先检查传入的USART指针和数据是否在有效范围内。发送数据:然后,它将数据写入USART的数据寄存器(DR)。等待发送完成:它使用循环等待,直到TXE(发送数据寄存器空)标志被设置,表示数据已被发送出去。USART_SendString(USART_TypeDef * USARTx, char *str)这个函数用于发送一个字符串。发送字符串:它遍历字符串,对每个字符调用USART_SendByte函数进行发送。等待传输完成:在所有字符发送后,它等待TC(传输完成)标志被设置,表示整个字符串已发送完成。USART_ReceiveByte(USART_TypeDef* USARTx)这个函数的目的是接收一个字节的数据,但你的代码片段中USART_ReceiveByte函数没有完整,我会假设其可能的实现。接收数据:它应该读取USART的数据寄存器(DR)来获取接收到的数据。清除中断标志:如果函数是为了中断驱动的接收而编写的,它还需要清除相应的中断标志。
实际工作状态:

发送接收回来的结果:

中文英文数字都可以收到:

总结:是重定义fputc函数,让他变成向上位机发送数据,发送的数据会通过串口调试助手打印出来。里面有接收函数,也发送,发送相关代码主要在函数里面实现。从这个串口代码中还是学到了如何使用串口的一些实用的功能,原来串口还可以这样用。
我要赚赏金
