实验需求
在串口输入相应的命令,控制对应的硬件进行操作
在串口输入led1on------>板子LED1灯点亮
在串口输入led1off------>板子LED1灯熄灭
在串口输入led2on------>板子LED2灯点亮
在串口输入led2off------>板子LED2灯熄灭
在串口输入led3on------>板子LED3灯点亮
在串口输入led3off------>板子LED3灯熄灭
编程要求:
1)结构体封装【头文件】
typedef struct{
char* cmd_arr; //命令字符串
gpio_t* gpiox; //gpio组号
unsigned int pin; //对应引脚编号
gpio_odr_t status; //对应引脚状态
void(*gpio_write)(gpio_t* gpiox,unsigned int pin, gpio_odr_t status);
}cmd_t;
2)对结构体数据初始化【头文件】
第一种方式:cmd_t arr[6] = {{"led1on",GPIOE,GPIO_PIN_10,GPIO_SET_T,hal_gpio_write},};
第二种方式:
cmd_t arr[6] = {
[0] ={
.cmd_arr = "led1on",
.gpiox = GPIOE,
.pin = GPIO_PIN_10,
.status = GPIO_SET_T,
.gpio_write = hal_gpio_write,
},
[1]={
},
};
3)串口工具输入的字符串如何与结构体每个元素中的cmd_arr成员进行比较【源代码】
1>需要定义一个变量,接收串口工具输入的字符串 char* buffer = hal_get_string();
2>输入的字符串与结构体每个元素中的cmd_arr成员进行比较---->需要自己编写比较函数strcmp
3>如果比较成功,代表查找到字符串,如果比较失败,代表没有查找到字符串
4)查找命令的比较函数
cmd_t* find_command(const char* buffer)
{
//输入的字符串与结构体每个元素中的cmd_arr成员进行比较
//需要自己编写比较函数strcmp
//成功结构体首地址
//比较失败返回0
}
5)主函数main.c如何进行编写?
char* buffer = hal_get_string(); //用来接收串口工具输入的字符串
cmd_t* p;
p = find_command(buffer);
if(p == 0)
{ //比较失败}
else
{
p->gpio_write(p->gpiox,p->pin,p->status);
}
头文件
#ifndef __WORK01__
#define __WORK01__
#include "stm32mp1xx_rcc.h"
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_uart.h"
//封装输出高低电平寄存器【正好是写的值】
typedef enum{
LED_OFF,
LED_ON
}gpio_odr_t;
typedef struct
{
char *cmd_arr; //命令字符串
gpio_t *gpiox; //gpio组号
unsigned int pin; //对应引脚编号
gpio_odr_t status; //对应引脚状态
void (*gpio_write)(gpio_t *gpiox, unsigned int pin, gpio_odr_t status);
}cmd_t;
//引脚封装
#define GPIO_PIN_0 0
#define GPIO_PIN_8 8
#define GPIO_PIN_10 10
/先发送字符串,接收字符串【uart串口实验】
//封装模式的寄存器
typedef enum{
INPUT,
OUTPUT,
ALT,
ANALOG
}gpio_moder_t;
//封装输出类型寄存器
typedef enum{
PUSH_PULL,
OPEN_DRAIN
}gpio_type_t;
//输出封装速率寄存器
typedef enum{
LOW,
MEDIUM,
HIGHT,
HIGHTER
}gpio_speeder_t;
//封装是否上下拉电阻寄存器
typedef enum{
NO,
PULL_UP,
PULL_DOWN,
RESERVED
}gpio_puper_t;
//使用结构体将寄存器放在一起
typedef struct{
gpio_moder_t moder; //封装的模式寄存器
gpio_type_t typer; //输出类型寄存器
gpio_speeder_t speeder; //输出速率寄存器
gpio_puper_t puper; //是否上下拉电阻寄存器
}gpio_init_t;
//初始化函数
void hal_uart_init();
//发送一个字符
void hal_put_char(const char str);
//发送一个字符串
void hal_put_string(const char *string);
//接收一个字符
char hal_get_char();
//接受一个字符串
char *hal_get_string();
/然后根据接收的字符串,控制相应的LED灯【LED灯实验】
//初始化函数(GPIO组号,初始化值,引脚编号)
void hal_gpio_init(gpio_t*gpiox, gpio_init_t* init, unsigned int pin_t);
//操作GPIO的接口写函数(GPIO组号,写的值,引脚编号)
void hal_gpio_write(gpio_t *gpiox, unsigned int pin, gpio_odr_t status);
cmd_t* find_command(const char* buffer);
#endif
源代码
#include "work01.h"
extern void delay_ms(int ms);
//三个LED灯的初始参数赋值结构体封装
cmd_t arr_control[6] = {
/
[0] = {
.cmd_arr = "led1on",
.gpiox = GPIOE,
.pin = GPIO_PIN_10,
.status = LED_ON,
.gpio_write = hal_gpio_write,
},
[1] = {
.cmd_arr = "led1off",
.gpiox = GPIOE,
.pin = GPIO_PIN_10,
.status = LED_OFF,
.gpio_write = hal_gpio_write,
},
/
[2] = {
.cmd_arr = "led2on",
.gpiox = GPIOF,
.pin = GPIO_PIN_10,
.status = LED_ON,
.gpio_write = hal_gpio_write,
},
[3] = {
.cmd_arr = "led2off",
.gpiox = GPIOF,
.pin = GPIO_PIN_10,
.status = LED_OFF,
.gpio_write = hal_gpio_write,
},
/
[4] = {
.cmd_arr = "led3on",
.gpiox = GPIOE,
.pin = GPIO_PIN_8,
.status = LED_ON,
.gpio_write = hal_gpio_write,
},
[5] = {
.cmd_arr = "led3off",
.gpiox = GPIOE,
.pin = GPIO_PIN_8,
.status = LED_OFF,
.gpio_write = hal_gpio_write,
}
};
//初始化函数
void hal_uart_init()
{
//不同于等的初始化,三个寄存器需要同时初始化
/**** RCC章节初始化 ****/
RCC->MP_AHB4ENSETR |= (0x1 << 1); //GPIOB组的使能 PB2
RCC->MP_AHB4ENSETR |= (0x1 << 6); //GPIOG组的使能 PG11
RCC->MP_APB1ENSETR |= (0x1 << 16); //UART4控制器的使能
/**** GPIO章节初始化 ****/
//打开stm32mp1xx_gpio.h可查看封装的相关寄存器
GPIOB->MODER &= (~(0x3 << 4)); //PB2引脚为复用功能
GPIOB->MODER |= (0x2 << 4);
GPIOB->AFRL &= (0xf << 8); //复用功能为RX
GPIOB->AFRL |= (0x8 << 8);
GPIOG->MODER &= (~(0x3 << 22)); //PG11引脚复用功能
GPIOG->MODER |= (0x2 << 22);
GPIOG->AFRL &= (0xf << 12); //复用功能为TX
GPIOG->AFRL |= (0x6 << 12);
/**** UART章节初始化 ****/
//判断UE位是否为0
if(USART4->CR1 & (0x1 << 0))
{
delay_ms(500);
USART4->CR1 &= (~(0x1 << 0));
}
//1、cr1 设置8位数据位,无奇偶校验位
USART4->CR1 &= ~(1 << 28);
USART4->CR1 &= ~(1 << 12);
//2、cr2设置1位停止位 13-12 = 00
USART4->CR2 &= ~(3 << 12);
//3、cr1串口16倍率 15-0
USART4->CR1 &= ~(1 << 15);
USART4->CR1 &= ~(1 << 10); //无奇偶校验位
//4、presc 设置串口不分频 3-0 ---- 0000
USART4->PRESC = 0x0;
//5、brr,串口波特率 115200 brr = 0x22b
USART4->BRR = 0x22B;
//6、cr1,串口te位使能
USART4->CR1 |= (1 << 3);
//7、cr1,串口re使能
USART4->CR1 |= (1 << 2);
//8、cr1,串口ue位使能
USART4->CR1 |= (1 << 0);
}
//发送一个字符【这里用不到发送字符串】
void hal_put_char(const char ch)
{
//判断发送数据寄存器是否为空ISR
//0:表示发送数据寄存器满,需要等待; 1:表示为空,发送下一个字节数据
while (!(USART4->ISR & (0x1 << 7)));
//循环语句结束,此时TXE=1,可以发送数据
//将需要发送的数据,放入到数据寄存器中
USART4->TDR = ch;
//判断发送数据寄存器是否发送完成【状态位】
while (!(USART4->ISR & (0x1 << 6)));
}
//发送一个字符串
void hal_put_string(const char *string)
{
//判断是否为\0,然后一个字符一个字符发送
const char *p = string;
while (*p)
{
hal_put_char(*p);
p++;
}
//没有此语句,输出会有很多空格
hal_put_char('\n');
hal_put_char('\r');
}
//接收一个字符
char hal_get_char()
{
char ch;
//判断接收数据寄存器是否有数据可读
while (!(USART4->ISR & (0x1 << 5)));
//此时表示有接收到数据
//将接收数据寄存器,赋值给新定义的变量,需要有个新的变量接收数据内容
ch = USART4->RDR;
return ch;
}
//接收一个字符串
char *hal_get_string()
{
static char buf[32] = "";
//接收之前需要手动写一个bzero的函数,手动将buf清零
for(int j = 0; j < 30; j++)
{
buf[j] = 0;
}
//循环进行接收
int i = 0;
while (1)
{
buf[i] = hal_get_char();
hal_put_char(buf[i]);
//判断字符是否为\r
if (buf[i] == '\r')
{
break;
}
i++;
}
buf[i] = '\0'; //接收的字符串结束
hal_put_char('\0');
hal_put_char('\n');
return buf;
}
/
//字符串比较函数实现
int string_cmp(const char* str1, const char* str2)
{
//返回0,表示字符串相同,否则不同
while(*str1 == *str2)
{
if(!(*str1)) //如果字符串结束,执行if条件语句
{
break;
}
else
{
str1++;
str2++;
}
}
return (*str1-*str2); //返回字符串之间的差值
}
/
//灯的初始化
void hal_gpio_init(gpio_t*gpiox, gpio_init_t* init, unsigned int pin_t)
{
//确定是E组还是F组的寄存器使能
if(gpiox == GPIOE)
{
RCC->MP_AHB4ENSETR |= (0x1 << 4); //设置GPIOE组的使能
}
else if(gpiox == GPIOF)
{
RCC->MP_AHB4ENSETR |= (0x1 << 5); //设置GPIOF组的使能
}
//讲MODER设置为输出模式,21,20设置为01
gpiox->MODER &= ~(0x3 << (pin_t*2)); //先清零
gpiox->MODER |= (init->moder << (pin_t*2)); //再置1
//设置输出类型,设置为推挽输出模式
gpiox->OTYPER &= ~(0x1 << pin_t);
gpiox->OTYPER |= (init->typer << pin_t);
//设置输出速率
gpiox->OSPEEDR &= ~(0x3 << (pin_t*2));
gpiox->OSPEEDR |= (init->speeder << (pin_t*2));
//PUPDR寄存器
gpiox->PUPDR &= ~(0x3 << (pin_t*2));
gpiox->PUPDR |= (init->puper << (pin_t*2));
}
//灯状态的写入
void hal_gpio_write(gpio_t *gpiox, unsigned int pin, gpio_odr_t status)
{
gpiox->ODR &= ~(0x1 << pin);
gpiox->ODR |= (status << pin);
}
/
//比较接收到的字符串是什么指令,然后控制不同的灯
cmd_t* find_command(const char* buffer)
{
for(int i = 0; i < 6; i++)
{
if(!string_cmp(buffer, arr_control[i].cmd_arr))
{
//字符串相同,返回结构体地址?
return &arr_control[i];
}
}
return 0;
}
主函数
#include "work01.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();
//led1灯初始参数赋值
gpio_init_t led1_init = {OUTPUT, PUSH_PULL, LOW, NO};
//对相应的寄存器初始化
hal_gpio_init(GPIOE, &led1_init, GPIO_PIN_10);
//led2灯初始参数赋值
gpio_init_t led2_init = {OUTPUT, PUSH_PULL, LOW, NO};
//对相应的寄存器初始化
hal_gpio_init(GPIOF, &led2_init, GPIO_PIN_10);
//led3灯初始参数赋值
gpio_init_t led3_init = {OUTPUT, PUSH_PULL, LOW, NO};
//对相应的寄存器初始化
hal_gpio_init(GPIOE, &led3_init, GPIO_PIN_8);
while (1)
{
//获取字符串
char *buf_temp = hal_get_string();
hal_put_string(buf_temp);
//对字符串进行比较,然后执行相应的动作
cmd_t *p_control = find_command(buf_temp);
if (p_control == 0)
{
hal_put_string("failed");
// return 0; //失败后直接退出程序
}
else
{
hal_put_string("good");
p_control->gpio_write(p_control->gpiox, p_control->pin, p_control->status);
delay_ms(500);
}
}
return 0;
}
运行结果示例
输入相应的指令可控制等的亮灭