前言
UART
什么是UART?
UART是通用异步收发器的缩写。它是一种用于在两个设备之间进行串行数据传输的通信接口。UART将数据以一系列的二进制位进行传输,并使用起始位、停止位和校验位来标识数据帧的开始和结束。UART使用串行通信方式,意味着数据是以单个位的形式连续传输的。这种方式的优势在于简单、易于实现,但是相对于其他的并行通信方式,传输速率要低得多。
GPIO
什么是GPIO?
GPIO(General-Purpose Input/Output)通常称作通用输入/输出,是一种在微处理器、微控制器或其他类型的计算机系统中用于连接外部设备和传输数据的接口。GPIO接口可以被编程为输入或输出,可以用于控制外部设备或读取外部设备的信号。
实验要求
实验要求:
串口输入相应的命令,,控制对应的硬件进行工作
例如:在串口工具输入LED1ON --------> LED1灯亮 PE10
在串口工具输入LED1OFF --------> LED1灯熄灭
在串口工具输入LED2ON --------> LED2灯亮 PF10
在串口工具输入LED2OFF --------> LED2灯熄灭
在串口工具输入LED3ON --------> LED3灯亮 PE8
在串口工具输入LED3OFF --------> LED3灯熄灭
实验过程
代码框架
1)结构体封装
typedef struct{
char* cmd_arr; //命令字符串
gpio_t* gpio; //gpio组号
unsigned int pin; //操作引脚编号
status_t status; //LED灯状态
void (*gpio_write_p)( gpio_t* gpio,unsigned int pin,status_t status);
}cmd_t;
2)结构体初始化
// 方式1:
cmd_t cmd_arr[6] = {{"LED1ON,GPIOE,GPIO_PIN_10,GPIO_SET,hal_gpio_write"},{},}
//方式2:
cmd_t cmd_arr[6] ={
[0] = {
.cmd_arr = LED1ON,
.gpio = GPIOE,
.pin = GPIO_PIN_10,
.status = GPIO_SET,
.gpio_write_p = hal_gpio_write,
},
[1] = {
},
};
3.在串口输入一个字符串
1)需要定义一个字符串指针变量,用来接收串口输入的字符串 char* string = get_string();
2)串口输入的字符串与结构体中的每个元素中的cmd_arr变量进行比较
3)如果比较成功,代表字符串相等,如果比较失败,代表字符串没有查找到
4.查找输入命令函数的编写要求
cmd_t* find_command(const char* str)
{
//函数功能实现:串口输入的字符串与结构体中的每个元素中的cmd_arr变量进行比较
//1.for循环遍历进行判断
//2.比较函数strcmp,注意这个strcmp函数需要自己进行编写
//3.如果成功,返回结构体首地址
//4.如果失败,返回0
}
5.注意:strcmp函数需要自己进行编写
6.main.c代码编写
char* string = get_string();
cmd_t* p;
p = find_command(string);
if( p == 0)
{
//失败
}else{
p->gpio_write_p(p->gpio,p->pin,.........);
}
代码编写
uart.c
#include "usart.h"
extern void delay_ms(int ms);
//uart4初始化
void hal_uart4_init()
{
/************RCC章节初始化**************/
//1.使能GPIOG控制器 MP_AHB4ENSETR[6] = 1
RCC->MP_AHB4ENSETR |= (0x1 << 6);
//2.使能GPIOB控制器 MP_AHB4ENSETR[1] = 1
RCC->MP_AHB4ENSETR |= (0x1 << 1);
//3.使能UART4控制器 MP_APB1ENSETR[16] = 1
RCC->MP_APB1ENSETR |= (0x1 << 16);
/********GPIO章节初始化**************/
//1.设置PB2引脚为复用功能模式 MODER[5:4] = 10
GPIOB->MODER &= (~(0x3 << 4));
GPIOB->MODER |= (0x1 << 5);
//2.设置PB2引脚复用功能为UART4_RX AFRL[11:8] = 1000
GPIOB->AFRL &= (~(0xf << 8));
GPIOB->AFRL |= (0x1 << 11);
//3.设置PG11引脚为复用功能模式 MODER[23:22] = 10
GPIOG->MODER &= (~(0x3 << 22));
GPIOG->MODER |= (0x1 << 23);
//4.设置PG11引脚的复用功能为UART4_TX AFRH[15:12] = 0110
GPIOG->AFRH &= (~(0xf << 12));
GPIOG->AFRH |= (0x3 << 13);
/********UART4章节初始化**************/
//0.需要判断串口UE位是否使能 CR1[0] = 1,后续操作只能在USART被禁用(UE-o)时被写入。
if(USART4->CR1 & 0x1)
{
delay_ms(500); //如果有数据等待数据发完
USART4->CR1 &= (~(0x1 << 0));
}
//1.设置UART4串口8为数据位 CR1[28][12] = 00
USART4->CR1 &= (~(0x1 << 12));
USART4->CR1 &= (~(0x1 << 28));
//2.设置UART4串口16倍采样率 CR1[15] = 0
USART4->CR1 &= (~(0x1 << 15));
//3.设置串口无奇偶校验位 CR1[10] = 0
USART4->CR1 &= (~(0x1 << 10));
//4.设置UART4串口1位停止位 CR2[13:12] = 00
USART4->CR2 &= (~(0x3 << 12));
//5.设置UART4串口不分频 PRESC[3:0] = 0000
USART4->PRESC &= (~(0xf << 0));
//6.设置UART4串口波特率为115200 BRR = 0x22b
USART4->BRR |= 0x22b;
//7.设置UART4串口接受器使能 CR1[3] = 1
USART4->CR1 |= (0x1 << 3);
//8.设置UART4串口发送器使能 CR1[2] = 1
USART4->CR1 |= (0x1 << 2);
//9.设置UART4 串口UE位使能 CR1[0] = 1
USART4->CR1 |= (0x1 << 0);
}
//发送一个字符
void put_char(const char str)
{
/*1.ISR[7]:判断发送数据寄存器是否为空
2.发送数据寄存器特点:如果发送数据寄存器为空,才可以发送下一个字节数据如果发送数据寄存器为满,需要等待发送数据寄存器为空
3.读0:发送数据寄存器为满,需要等待
读1:发送数据寄存器为空,可以发送下一个字节数据*/
while (!(USART4->ISR &(0x1 << 6)));
USART4->TDR = str;
/*1.ISR[6]:判断发送数据寄存器是否完成
2.特点:如果发送数据寄存器,发送数据完成,才可以发送下一帧数据
如果发送数据寄存器,发送数据没有完成,不可以发送下一帧数据,需要等待发送数据完成
3.读0:发送数据没有完成,需要等待
读1发送数据完成,可以发送下一帧数据*/
while (!(USART4->ISR &(0x1 << 6)));
}
//发送一个字符串
void put_string(const char* string)
{
//将字符串一个一个字符发送
while(*string)
{
put_char(*string++);
}
put_char('\n');
put_char('\r'); //回车
}
//接收一个字符
char get_char()
{
char str;
/*1.ISR[5]:判断接收数据寄存器是否为空
2.特点:如果接收数据寄存器接收到数据,才可以读
如果接收数据寄存器没有接收到数据,没有数据可读,需要等待
3.读0:没有接收到数据,需要等待
读1:接收到数据,有数据可读*/
while(!(USART4->ISR & (0x1 << 5)));
str = USART4->RDR;
return str;
}
//接收一个字符串
char buf[50]={0}; //不能返回局部变量的地址
char *get_string()
{
//循环接收
int i =0;
for(i=0;i<49;i++)
{
buf[i]=get_char();
put_char(buf[i]);
if(buf[i]=='\r')
{
break;
}
}
buf[i]='\0';
put_char('\n');
return buf;
}
gpio.c
#include "gpio.h"
//字符串比较
int strcmp(char *str1, char *str2)
{
while(*str1 == *str2) //比较两个字符串
{
if(*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2; //返回值
}
// 初始化GPIO
void hal_gpio_init(gpio_t *gpiox, gpio_init_t *init, unsigned int pin)
{
// 设置输出模式
gpiox->MODER &= (~(0x3 << (pin * 2)));
gpiox->MODER |= (init->moder << (pin * 2));
// 设置输出类型
gpiox->OTYPER &= (~(0x1 << pin));
gpiox->OTYPER |= (init->otyper << pin);
// 设置输出速率
gpiox->OSPEEDR &= (~(0x3 << (pin * 2)));
gpiox->OSPEEDR |= (init->speed << (pin * 2));
// 是否上下拉电阻
gpiox->PUPDR &= (~(0x3 << (pin * 2)));
gpiox->PUPDR |= (init->pupdr << (pin * 2));
}
// 初始化cmd结构体
cmd_t cmd_arr[7] = {
[0] = {
.cmd_arr = "LED1 ON",
.gpio=GPIOE,
.pin=10,
.status=GPIO_SET,
.hal_gpio_write=hal_gpio_write
},
[1] = {
.cmd_arr = "LED1 OFF",
.gpio=GPIOE,
.pin=10,
.status=GPIO_RESET,
.hal_gpio_write=hal_gpio_write
},
[2] = {
.cmd_arr = "LED2 ON",
.gpio=GPIOF,
.pin=10,
.status=GPIO_SET,
.hal_gpio_write=hal_gpio_write
},
[3] = {
.cmd_arr = "LED2 OFF",
.gpio=GPIOF,
.pin=10,
.status=GPIO_RESET,
.hal_gpio_write=hal_gpio_write
},
[4] = {
.cmd_arr = "LED3 ON",
.gpio=GPIOE,
.pin=8,
.status=GPIO_SET,
.hal_gpio_write=hal_gpio_write
},
[5] = {
.cmd_arr = "LED3 OFF",
.gpio=GPIOE,
.pin=8,
.status=GPIO_RESET,
.hal_gpio_write=hal_gpio_write
},
[6] = {
.cmd_arr = "NOT FOUND !!!",
.gpio=0,
.pin=0,
.status=0,
.hal_gpio_write=hal_gpio_write
},
};
// 函数功能:操作GPIO引脚,实现亮灭
void hal_gpio_write(gpio_t * gpiox, unsigned int pin, gpio_status_t status)
{
if (status == GPIO_SET)
{
gpiox->ODR |= (0x1 << pin);
}
else
{
gpiox->ODR &= (~(0x1 << pin));
}
}
//查找命令字符串
cmd_t *find_command(char* str)
{
unsigned int i;
for(i=0;i<6;i++)
{
if(!(strcmp(str,cmd_arr[i].cmd_arr)))
{
return &cmd_arr[i];
}
}
return &cmd_arr[6];
}
mian.c
#include "usart.h"
#include "gpio.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++);
}
void LED_init()
{
//时钟使能
RCC->MP_AHB4ENSETR |=(0x3<<4);
//RCC_AHB4_ENSETR |=(0x1<<5);
//初始化结构体
gpio_init_t init={OUTPUT,PP,LOW,NO_PUPD};
//LED初始化
hal_gpio_init(GPIOE,&init,10); //LED1
hal_gpio_init(GPIOF,&init,10); //LED2
hal_gpio_init(GPIOE,&init,8); //LED3
}
int main()
{
LED_init();
hal_uart4_init();
cmd_t *cmd;
while(1)
{
char *str= get_string();
cmd = find_command(str);
if(cmd->gpio==0)
{
put_string("NOT FOUND !!!");
}
else
{
cmd->hal_gpio_write(cmd->gpio,cmd->pin,cmd->status);
}
}
return 0;
}