分析过程:
框图:
通过以上框图分析可知,需要分析芯片手册 RCC / GPIO / UART
1.RCC章节:使能对应GPIOG/GPIOB/UART4控制器
2.GPIO章节:1)设置引脚为复用功能模式 2)设置复用功能为串口功能
3.UART章节:1)串口初始化相关操作 2)数据收发
确定总线连接:
基地址:
分析RCC章节的寄存器:
1.如何确定RCC_MP_AHB4ENSETR地址?
RCC_MP_AHB4ENSETR地址 = 基地址 + 偏移地址 = 0x50000000 + 0xA28 = 0x50000A28
2.如何通过RCC_MP_AHB4ENSETR寄存器,设置GPIOB/GPIOG组控制器使能?
PB2 / PG11 RCC_MP_AHB4ENSETR[1] = 1
[0x50000A28]第1位写1 ------>GPIOB组控制器使能
RCC_MP_AHB4ENSETR[6] = 1
[0x50000A28]第6位写1 ------>GPIOG组控制器使能
1.如何确定RCC_MP_APB1ENSETR地址?
RCC_MP_APB1ENSETR地址 = 基地址 + 偏移地址 = 0x50000000 + 0xA00 = 0x50000A00
2.如何通过RCC_MP_APB1ENSETR寄存器,设置UART4组控制器使能? RCC_MP_APB1ENSETR[16] = 1
[0x50000A00]第16位写1 ------>UART4组控制器使能
GPIO章节的寄存器:
GPIOx_MODER寄存器:GPIO模式寄存器 作用:设置GPIO引脚模式
1.确定GPIOB_MODER / GPIOG_MODER 地址是多少?
GPIOB_MODER地址 = 基地址 + 偏移地址 = 0x50003000 + 0x00 = 0x50003000
GPIOG_MODER地址 = 基地址 + 偏移地址 = 0x50008000 + 0x00 = 0x50008000
2.通过GPIOB_MODER寄存器设置PB2引脚为复用功能模式?
GPIOB_MODER[5:4] = 10
0x50003000[5:4] = 10
3.通过GPIOG_MODER寄存器设置PG11引脚为复用功能模式?
GPIOG_MODER[23:22] = 10
0x50008000[23:22] = 10
GPIOx_AFRL寄存器功能:设置引脚为复用功能
1.确定GPIOB_AFRL地址是多少?
GPIOB_AFRL地址 = 基地址 + 偏移地址 = 0x50003000 + 0x20 = 0x50003020
2.通过GPIOB_AFRL 寄存器设置PB2引脚为复用功能模式为UART4_RX?
GPIOB_AFRL[11:8] = 1000
3.在查找对应的复用功能时,需要借助stm32mp157a.pdf中Table8和Table9
D:\新平台\fsmp1a(学生资料)\stm32mp157-学生资料\stm32mp157-学生资料\01_参考资料\01.1_数据手册/stm32mp157a.pdf
GPIOx_AFRH寄存器功能:设置引脚为复用功能
1.确定GPIOG_AFRH地址是多少?
GPIOG_AFRH地址 = 基地址 + 偏移地址 = 0x50008000 + 0x24 = 0x50008024
2.通过GPIOG_AFRH寄存器设置PG11引脚为复用功能模式为UART4_TX?
GPIOG_AFRH[15:12] = 0110
3.在查找对应的复用功能时,需要借助stm32mp157a.pdf中Table8和Table9
D:\新平台\fsmp1a(学生资料)\stm32mp157-学生资料\stm32mp157-学生资料\01_参考资料\01.1_数据手册/stm32mp157a.pdf
USART章节:
通过以上章节分析可知,需要分析以下寄存器
1.USART_CR1:设置数据位宽度,以及将对应位使能
2.USART_CR2:设置停止位位数
3.USART_BRR:设置串口波特率
4.USART_TDR:发送数据寄存器
5.USART_RDR:接收数据寄存器
6.USART_PRESC:设置串口分频器
7.需要去寄存器中查找TXE和TC位标志,对应哪一个寄存器 ------>USART_ISR寄存器
USART_CR1寄存器作用:初始化串口
1.USART_CR1地址是多少?
USART_CR1地址 = 基地址 + 偏移地址 = 0x40010000 + 0x00 = 0x40010000
2.USART_CR1寄存器需要配置内容
USART_CR1[28][12] = 00 ------->设置8位数据位
USART_CR1[15] = 0 -------> 设置16倍采样率
USART_CR1[10] = 0 -------> 设置串口无奇偶校验位
USART_CR1[3] = 1 -------> 设置串口发送器使能
USART_CR1[2] = 1 -------> 设置串口接收器使能
USART_CR1[20 = 1 -------> 设置串口使能
USART_CR2寄存器作用:初始化串口
1.USART_CR2地址是多少?
USART_CR2地址 = 基地址 + 偏移地址 = 0x40010000 + 0x04 = 0x40010004
2.USART_CR2寄存器需要配置内容
USART_CR2[13:12] = 00 ------->设置串口1位停止位
USART_BRR寄存器作用:设置串口波特率为115200
1.USART_BRR地址是多少?
USART_BRR地址 = 基地址 + 偏移地址 = 0x40010000 + 0x0C = 0x4001000C
2.如果想知道USART_BRR寄存器需要设置的值,需要参考53.5.7章节,确认串口提供的主频64MHZ,并且设置波特率为115200
USART_BRR = 64000000 / 115200 = 0x22B
USART_ISR[7]:判断发送数据寄存器是否为空,为空才可以发送下一个字节数据,为满需要等待发送数据寄存器为空
读0:发送数据寄存器满,需要等待发送数据寄存器为空
读1:发送数据寄存器空,可以发送下一个字节数据
USART_ISR[6]:判断发送数据是否完成,表示一帧数据是否发送完成
读0:发送数据没有完成
读1:发送数据完成
USART_ISR[5]:判断接收数据寄存器是否不为空,只有接收到数据才可以读
读0:没有接收到数据
读1:接收到数据
作业:串口实现字符串、字符的收发:
main.c:
#include "uart4.h"
extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
int i,j;
for(i = 0; i < ms;i++)
for (j = 0; j < 1800; j++);
}
int main()
{
hal_uart_init();
while(1)
{
//hal_putchar(hal_recvchar()+1);
hal_putstring(hal_recvstring());
}
return 0;
}
头文件:
#ifndef __UART4__
#define __UART4__
//初始化函数
void hal_uart_init();
//发送一个字符
void hal_putchar(const char str);
//发送一个字符串
void hal_putstring(const char *string);
//接收一个字符串
char hal_recvchar();
//接收一个字符串
char *hal_recvstring();
#endif
函数文件:
#include "uart4.h"
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_uart.h"
//初始化函数
void hal_uart_init(){
//RCC
RCC->MP_AHB4ENSETR |= (1 << 1);
RCC->MP_AHB4ENSETR |= (1 << 6);
RCC->MP_APB1ENSETR |= (1 << 16);
//GPIO
GPIOB->MODER &= ~(3 << 4);
GPIOB->MODER |= (2 << 4);
GPIOB->AFRL &= ~(15 << 8);
GPIOB->AFRL |= (8 << 8);
GPIOG->MODER &= ~(3 << 22);
GPIOG->MODER |= (2 << 22);
GPIOG->AFRH &= ~(0 << 12);
GPIOG->AFRH |= (6 << 12);
//UART4
USART4->CR1 &= ~(1 << 28);
USART4->CR1 &= ~(1 << 12);
USART4->CR1 &= ~(1 << 10);
USART4->CR2 &= ~(3 << 12);
USART4->CR1 &= ~(1 << 15);
USART4->PRESC = 0x0;
USART4->BRR = 0x22B;
USART4->CR1 |= (1 << 3);
USART4->CR1 |= (1 << 2);
USART4->CR1 |= (1 << 0);
}
//发送一个字符
void hal_putchar(const char str){
//判断发送数据寄存器是否为空
while(!(USART4->ISR & (0x1 << 7)));
//将要发送的数据,放入到发送数据寄存器中
USART4->TDR = str;
//判断发送数据寄存器是否发送完成
while(!(USART4->ISR & (0x1 << 6)));
}
//发送一个字符串
void hal_putstring(const char *string){
//判断是否为'\0',一个字符一个字符进行发送
int n = 0;
while(1){
while(!(USART4->ISR & (0x1 << 7)));
USART4->TDR = *(string + n);
while(!(USART4->ISR & (0x1 << 6)));
if(*(string+n) == '\r'){
break;
}
n ++;
}
hal_putchar('\n');
}
//接收一个字符
char hal_recvchar(){
//判断接收数据寄存器种是否有数据可读
while(!(USART4->ISR &(0x1 << 5)));
//将接收数据寄存器的内容,赋值给ch
static char ch;
ch = USART4->RDR;
return ch;
}
char *hal_recvstring(){
static char *str = "\0";
int n = 0;
while(1){
while(!(USART4->ISR &(0x1 << 5)));
*(str+n) = USART4->RDR;
hal_putchar(*(str+n));
if(*(str+n) == '\r'){
hal_putchar('\n');
break;
}
n ++;
}
return str;
}
结果如下:
字符串:
字符: