LED点灯实验
一.电路图:
三极管:
NPN类型:
PNP类型:
NPN类型当基极为高电平时,集电极和发射极导通
PNP类型当基极为低电平时,集电极和发射极导通
由电路图可知LED电路图中三极管为NPN类型,只有当基极为高电平时,集电极和发射极导通,LED亮起。因此LED亮起为高电平,LED熄灭为低电平
LED1----PE10
LED2----PF10
LED3----PE8
- 分析RCC章节
作用:使能GPIO
RCC在AHB4总线上(芯片手册第二章),通过RCC_MP_AHB4ENSETR寄存器使能GPIOE组和GPIOF组相关控制器
- 分析GPIO章节
GPIO框图
- MOS管:栅极为低电平时,源极和漏极导通
- MOS管:栅极为高电平时,源极和漏极导通
GPIO相关寄存器
GPIO_MODER: 选择输出模式
GPIO_OTYPER:选择输出类型
GPIO_SPEEDR:选择输出速率
GPIO_PUPDR:选择是否需要上下拉电阻
GPIO_ODR:控制输出高电平还是低电平
代码:
gpio.h:
#ifndef __GPIO_H__
#define __GPIO_H__
//寄存器封装
typedef struct{
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
}gpio_t;
#define GPIOE ((gpio_t*)0x50006000)
#define GPIOF ((gpio_t*)0x50007000)
#define RCC_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28)
//封装引脚
#define GPIO_PIN_0 0
#define GPIO_PIN_1 1
#define GPIO_PIN_2 2
#define GPIO_PIN_3 3
#define GPIO_PIN_4 4
#define GPIO_PIN_5 5
#define GPIO_PIN_6 6
#define GPIO_PIN_7 7
#define GPIO_PIN_8 8
#define GPIO_PIN_9 9
#define GPIO_PIN_10 10
#define GPIO_PIN_11 11
#define GPIO_PIN_12 12
#define GPIO_PIN_13 13
#define GPIO_PIN_14 14
#define GPIO_PIN_15 15
//模式寄存器封装
typedef enum{
INPUT,
OUTPUT,
ALT,
ANALOG
}gpio_moder_t;
//输出类型寄存器封装
typedef enum{
PP,
OD
}gpio_otyper_t;
//输出速率寄存器封装
typedef enum{
LOW,
MED,
HIGH,
VERY_HIGH
}gpio_ospeedr_t;
//是否需要上下拉电阻封装
typedef enum{
NO_PUPD,
PU,
PD
}gpio_pupdr_t;
//输出高低电平寄存器封装
typedef enum{
GPIO_RESET,
GPIO_SET
}gpio_status_t;
//封装初始化结构体
typedef struct{
gpio_moder_t moder; //模式
gpio_otyper_t otyper; //输出类型
gpio_ospeedr_t speed;//速率
gpio_pupdr_t pupdr; //是否需要上下拉电阻
}gpio_init_t;
//函数功能:初始化GPIO(根据参数初始化不同LED)
void hal_gpio_init(gpio_t* gpiox,gpio_init_t* init,unsigned int pin);
//函数功能:操作GPIO引脚,实现LED灯亮灭
void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t status);
#endif
gpio.c:
#include "gpio.h"
void hal_gpio_init(gpio_t* gpiox,gpio_init_t* init,unsigned int pin)
{
gpiox->MODER&=(~(0x3<<(pin*2)));//设置IO口模式为输出模式
gpiox->MODER|=(init->moder)<<(pin*2);
gpiox->OTYPER&=~(0x1<<(pin));//设置输出类型为推挽类型
gpiox->OTYPER|=(init->otyper)<<(pin);
gpiox->OSPEEDR&=~(0x3<<(pin*2));//设置输出速率为低速
gpiox->OSPEEDR|=(init->otyper)<<(pin*2);
gpiox->PUPDR&=~(0x3<<(pin*2));//设置不需要上下拉电阻
gpiox->PUPDR|=(init->pupdr)<<(pin*2);
}
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);//写入低电平
}
}
main.c:
#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()
{
//1.时钟使能
RCC_AHB4_ENSETR|=(0x3<<4);
//2.初始化结构体
gpio_init_t init={OUTPUT,PP,LOW,NO_PUPD};
//3.调用gpio初始化函数
hal_gpio_init(GPIOE,&init,10);
hal_gpio_init(GPIOF,&init,10);
hal_gpio_init(GPIOE,&init,8);
}
int main()
{
led_init();
while(1)
{
hal_gpio_write(GPIOE,10,GPIO_SET);
delay_ms(1000);
hal_gpio_write(GPIOE,10,GPIO_RESET);
hal_gpio_write(GPIOF,10,GPIO_SET);
delay_ms(1000);
hal_gpio_write(GPIOF,10,GPIO_RESET);
hal_gpio_write(GPIOE,8,GPIO_SET);
delay_ms(1000);
hal_gpio_write(GPIOE,8,GPIO_RESET);
}
return 0;
}
串口解析器
led.h
#ifndef __LED_H__
#define __LED_H__
#include "../common/include/stm32mp1xx_gpio.h"
/*
//LED1初始化
void led1_init();
//LED1点亮
void led1_on();
//LED1熄灭
void led1_off();
*/
#define GPIO_PIN_0 0
#define GPIO_PIN_1 1
#define GPIO_PIN_2 2
#define GPIO_PIN_3 3
#define GPIO_PIN_4 4
#define GPIO_PIN_5 5
#define GPIO_PIN_6 6
#define GPIO_PIN_7 7
#define GPIO_PIN_8 8
#define GPIO_PIN_9 9
#define GPIO_PIN_10 10
#define GPIO_PIN_11 11
#define GPIO_PIN_12 12
#define GPIO_PIN_13 13
#define GPIO_PIN_14 14
#define GPIO_PIN_15 15
typedef enum{
GPIO_RESET,
GPIO_SET
}gpio_status_t;
typedef struct{
char* cmd_str; //字符串
gpio_t* gpiox; //GPIO组
unsigned int pin; //引脚
gpio_status_t stat; //LED状态
void (*gpio_write_p)(gpio_t* gpiox,unsigned int pin,gpio_status_t stat);
}cmd_t;
void hal_gpio_init();
void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t stat);
void put_char(const char c);
char get_char();
char* get_string();
cmd_t* cmp_str(char* str);
int my_strcmp(char* str1 ,char* str2);
void put_string(char* string);
#endif
led.c
#include "../include/led.h"
#include "../common/include/stm32mp1xx_gpio.h"
#include "../common/include/stm32mp1xx_rcc.h"
#include "../common/include/stm32mp1xx_uart.h"
extern void printf(const char *fmt, ...);
//初始化/
void hal_gpio_init(){
RCC->MP_AHB4ENSETR|=0x1<<4;
RCC->MP_AHB4ENSETR|=0x1<<5;
//LED1----PE10
GPIOE->MODER&=(~(0x3)<<20);
GPIOE->MODER|=(0x1<<20);
GPIOE->OTYPER&=(~(0x1<<10));
GPIOE->OSPEEDR&=(~(0x3<<20));
GPIOE->PUPDR&=(~(0x3<<20));
//LED2----PF10
GPIOF->MODER&=(~(0x3)<<20);
GPIOF->MODER|=(0x1<<20);
GPIOF->OTYPER&=(~(0x1<<10));
GPIOF->OSPEEDR&=(~(0x3<<20));
GPIOF->PUPDR&=(~(0x3<<20));
//LED3----PE8
GPIOE->MODER&=(~(0x3)<<16);
GPIOE->MODER|=(0x1<<16);
GPIOE->OTYPER&=(~(0x1<<8));
GPIOE->OSPEEDR&=(~(0x3<<16));
GPIOE->PUPDR&=(~(0x3<<16));
//UART
RCC->MP_AHB4ENSETR |= (0x1 << 1);
RCC->MP_AHB4ENSETR |= (0x1 << 6);
// 使能UART控制器的时钟
RCC->MP_APB1ENSETR |= (0x1 << 16);
/*******GPIO章节初始化*******/
// 设置PG11为复用模式
GPIOG->MODER &= (~(0x3 << 22));
GPIOG->MODER |= (0x2 << 22);
//设置PB2为复用模式
GPIOB->MODER &= (~(0x3 << 4));
GPIOB->MODER |= (0x2 << 4);
//设置PG11为UART4_TX复用功能
GPIOG->AFRH &= (~(0xf << 12));
GPIOG->AFRH |= (0x6 << 12);
//设置PB2为UART4_RX复用功能
GPIOB->AFRL &= (~(0xf << 8));
GPIOB->AFRL |= (0x8 << 8);
/*******UART章节初始化*******/
//设置UART4传输数据宽度为8位
USART4->CR1 &= (~(0x1 << 28));
USART4->CR1 &= (~(0x1 << 12));
//设置UART4串口16倍采样率
USART4->CR1 &= (~(0x1 << 15));
//设置UART4串口无奇偶校验位
USART4->CR1 &= (~(0x1 << 10));
//设置UART4串口发送寄存器和接收寄存器使能
USART4->CR1 |= (0x3 << 2);
//设置UART4串口1位停止位
USART4->CR2 &= (~(0x3 << 12));
//设置UART4串口不分频
USART4->PRESC &= ~0xf;
//设置UART4串口波特率为115200
USART4->BRR &= ~0xffff;
USART4->BRR |= 0x22b;
//设置UART4串口使能
USART4->CR1 |= 0x1;
}
//初始化结构体
cmd_t cmd_arr[6]={
[0]={
.cmd_str="LED1ON",
.gpiox=GPIOE,
.pin=GPIO_PIN_10,
.stat=GPIO_SET,
.gpio_write_p=hal_gpio_write,
},
[1]={
.cmd_str="LED1OFF",
.gpiox=GPIOE,
.pin=GPIO_PIN_10,
.stat=GPIO_RESET,
.gpio_write_p=hal_gpio_write,
},
[2]={
.cmd_str="LED2ON",
.gpiox=GPIOF,
.pin=GPIO_PIN_10,
.stat=GPIO_SET,
.gpio_write_p=hal_gpio_write,
},
[3]={
.cmd_str="LED2OFF",
.gpiox=GPIOF,
.pin=GPIO_PIN_10,
.stat=GPIO_RESET,
.gpio_write_p=hal_gpio_write,
},
[4]={
.cmd_str="LED3ON",
.gpiox=GPIOE,
.pin=GPIO_PIN_8,
.stat=GPIO_SET,
.gpio_write_p=hal_gpio_write,
},
[5]={
.cmd_str="LED3OFF",
.gpiox=GPIOE,
.pin=GPIO_PIN_8,
.stat=GPIO_RESET,
.gpio_write_p=hal_gpio_write,
}
};
// 2.发送一个字符
void put_char(const char str)
{
while (!(USART4->ISR & (0x1 << 7)));
USART4->TDR = str;
while (!(USART4->ISR & (0x1 << 6)));
}
// 3.发送一个字符串
void put_string( char *str)
{
while (*str)
{
put_char(*str++);
}
put_char('\n');
put_char('\r');
}
// 4.接收一个字符
char get_char()
{
char ch;
while (!(USART4->ISR & (0x1 << 5)));
ch = USART4->RDR;
return ch;
}
char buffer[50] = {0};
char *get_string()
{
unsigned int i;
for (i = 0; i < 49; i++)
{
buffer[i] = get_char();
put_char(buffer[i]);
if (buffer[i] == '\r')
break;
}
buffer[i] = '\0';
put_char('\n');
return buffer;
}
int my_strcmp(char* str1,char* str2){ //比较字符串
while ((*str1 != '\0') && (*str1 == *str2))//判断字符串是否结束。
{
str1++;
str2++;//
}
int t;
t = *str1 - *str2;//比较对应字符大小。
if (t == 0)
printf("same string\n");
else if (t > 0)
printf("str1 is bigger\n");
else
printf("str2 is bigger\n");
return t;//若相等返回0,前者大返回正值,反之则负。
}
cmd_t* cmp_str(char* str) //循环比较字符串和结构体数组中的字符串
{
for(unsigned int i=0;i<6;i++){
if(my_strcmp(str,cmd_arr[i].cmd_str)==0){
return &cmd_arr[i];
}
}
return 0;
}
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);
}
}
main.c
#include "led.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_gpio_init();
char* string="";
cmd_t *p;
while(1)
{
string=get_string();
printf("%s\n",string);
p=cmp_str(string);
if(p==0){
put_char('n'); //测试
}else{
put_char('y'); //测试
p->gpio_write_p(p->gpiox,p->pin,p->stat);
}
}
return 0;
}