UART编程
1、原理图
(1)选择串口1:TX对应PA9引脚;RX对应PA10引脚。

2、配置引脚为UART功能
2.1、模块的基地址
串口的TX和RX引脚使用了GPIOA,所以需要使能GPIOA模块。
- 0x4002 3800 :RCC基地址
- 0x4002 0000 :GPIOA基地址
- 0x4001 1000 :USART1基地址

2.2、使能GPIOA和USART1模块
(1)使能GPIOA

(2)使能USART1模块

2.3、配置TX和RX引脚
(1)从原理图可知:
- PA9有多种功能:PA9/TIM1_CH2/I2C3_SMBA/U1_TX/DCMI_D0/OTG_FS_VBUS。
- PA10也有多种功能:PA10/TIM1_CH3/U1_RX/OTG_FS_ID/DCMI_D1
(2)配置为复用功能模式

(3)配置速率为25MHz。

(4)复用功能选择

3、设置串口参数
(1)波特率

(2)数据位 & 校验位
- bit13置1:使能串口
- bit12清0:数据位配置为8位
- bit10置1:使能奇偶校验
- bit9清0:配置为偶校验
- bit3置1:发送器使能
- bit2置1:使能接收器



(4)停止位:配置1个停止为。

4、根据状态寄存器读写数据
(1)说明:
- 肯定有一个数据寄存器,程序把数据写入,即刻通过串口向外发送数据
- 肯定有一个数据寄存器,程序读取这个寄存器,就可以获得先前接收到的数据
- 状态寄存器
- 发送状态:判断数据是否发送出去?是否发送成功?
- 接收状态:判断是否接收到了数据?
(2)状态寄存器


(3)数据寄存器:写、读这个寄存器,就可发送、读取串口数据。

5、程序
(1)start.s文件
PRESERVE8THUMB; Vector Table Mapped to Address 0 at ResetAREA RESET, DATA, READONLYEXPORT __Vectors__Vectors DCD 0 DCD Reset_Handler ; Reset HandlerAREA |.text|, CODE, READONLY; Reset handler
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT mainLDR SP, =(0x20000000+0x30000)BL mainENDP END(2)main.c文件
#include <stdio.h>
#include "uart.h"int main()
{char c = 0;uart_init();uart_putchar('h');uart_putchar('e');uart_putchar('l');uart_putchar('l');uart_putchar('0');uart_putchar('\r');uart_putchar('\n');while (1){c = uart_getchar(); /* 从串口接收一个字符 */uart_putchar(c);uart_putchar(c+1);}
}(3)uart.c文件
#include <stdio.h>
#include "uart.h"typedef unsigned int uint32_t;
typedef struct
{volatile uint32_t SR; /* 状态寄存器, 地址偏移: 0x00 */volatile uint32_t DR; /* 数据寄存器, 地址偏移: 0x04 */volatile uint32_t BRR; /* 波特率寄存器, 地址偏移: 0x08 */volatile uint32_t CR1; /* 控制寄存器1, 地址偏移: 0x0C */volatile uint32_t CR2; /* 控制寄存器2, 地址偏移: 0x10 */volatile uint32_t CR3; /* 控制寄存器3, 地址偏移: 0x14 */volatile uint32_t GTPR; /* 保护时间和预分频寄存器, 地址偏移: 0x18 */
} USART_TypeDef;void uart_init(void)
{volatile unsigned int *pReg = NULL;pReg = (unsigned int *)(0x40023800 + 0x30);*pReg |= (0x01 << 0); /* 使能GPIOA */pReg = (unsigned int *)(0x40023800 + 0x44);*pReg |= (0x01 << 4); /* 使能USART1 */pReg = (unsigned int *)(0x40020000 + 0x00); /* UART_TX PA9配置为复用模式 */*pReg |= (0x02 << 18);pReg = (unsigned int *)(0x40020000 + 0x00); /* UART_RX PA10配置为复用模式 */*pReg |= (0x02 << 20);pReg = (unsigned int *)(0x40020000 + 0x08); /* UART_TX PA9输出速率为25MHz */*pReg |= (0x01 << 18);pReg = (unsigned int *)(0x40020000 + 0x24); /* UART_TX PA9复用为串口模式 */*pReg |= (0x07 << 4);pReg = (unsigned int *)(0x40020000 + 0x24); /* UART_RX PA10复用为串口模式 */*pReg |= (0x07 << 8);pReg = (unsigned int *)(0x40020000 + 0x0C); /* PA9上拉配置 */*pReg |= (0x01 << 18); /* PA9上拉,确保空闲时高电平 */USART_TypeDef *usart1 = (USART_TypeDef *)0x40011000;#define DIV_Mantissa 0x08
#define DIV_Fraction 0x11usart1->BRR = (DIV_Mantissa<<4) | (DIV_Fraction);usart1->CR1 |= (0x01 << 13); /* 设置UE位,使能USART */usart1->CR1 &= ~(0x01 << 12); /* 清除M位,选择8位数据位 */usart1->CR1 &= ~(0x01 << 10); /* 清除PCE位,禁止奇偶校验控制 */usart1->CR1 |= (0x01 << 3); /* 设置TE位,使能发送 */usart1->CR1 |= (0x01 << 2); /* 设置RE位,使能接收 */usart1->CR2 &= ~(0x03 << 12); /* 清除STOP位,配置1个停止位 */
}int uart_getchar(void)
{USART_TypeDef *usart1 = (USART_TypeDef *)0x40011000;while((usart1->SR & (0x01 << 5)) == 0); /* 等待接收数据寄存器非空 */return (usart1->DR & 0x00FF); /* 返回接收到的字符 */
}int uart_putchar(char c)
{USART_TypeDef *usart1 = (USART_TypeDef *)0x40011000;while((usart1->SR & (0x01 << 7)) == 0); /* 等待发送数据寄存器为空 */usart1->DR = (c & 0x00FF); /* 发送字符 */return c; /* 返回发送的字符 */
}
(4)uart.h文件
#ifndef __UART_H__
#define __UART_H__void uart_init(void);
int uart_getchar(void);
int uart_putchar(char c);#endif

