嵌入式设计与开发项目-LED指示灯程序设计
一、实现的功能与效果
实现的效果:8个LED的流水灯控制,每隔1s点亮一个灯,按以上步骤重复进行
二、根据功能实现代码
1、主文件main.c
#include "led.h" //需要自定义led.h头文件
unsigned char ucLed=1;
unsigned long ulTick_ms; //计数进行延时
int main(void)
{
SysTick_Config(72000); //定时1ms(HCLK = 72MHz)
LED_Init(); //初始化LED对应的GPIO引脚
while(1);
}
//系统中断服务函数,1ms中断一次
void SysTick_Handler(void)
{
ulTick_ms++; //每经过1ms,ulTick_ms加1
if(ulTick_ms == 1000)
{
ucLed <<=1; //1s左移一位0000 0010
if(ucLed == 0)
ucLed =1; //因为char类型占用1个字节,超出8位后重新开始移位
LED_Disp(ucLed); //点亮对应的位的LED灯
}
}
主函数分析:❤️ ❤️ ❤️
- 需要定义一个led.h头文件,需要包含LED_Init()初始化函数和LED_Disp(unsigned char ucLed)函数,同时在定义一个led.c文件实现以上两个函数。
- 设置时钟频率为72MHz,每经过1ms运行一次SysTick_Handle()中断服务函数一次;
2、自定义led.h头文件
/**************
防止头文件重复的定义,在项目中常用到
#ifndef __LED_H__
#define __LED_H__
***
***
***
#endif
**************/
#include "stm32f10x.h"
void LED_Init(void);
void LED_Disp(unsigned char ucLed);
void BUZ_Init(void); //暂时没有使用到,蜂鸣器初始化的函数
简要分析:❤️ ❤️
- 因为引脚初始化会使用固件库的函数,需包含"stm32f10x.h";
- 声明led.c的实现函数,方便其它函数的调用;
3、led.c源文件实现函数
#include "led.h"
// LED接口初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//允许、使能GPIOC和GPIOD时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
//PC8~PC15通用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |\
GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //配置GPIO的引脚、速度、模式
GPIO_Init(GPIOC,&GPIO_InitStruct); //初始化结构体
//PD2通用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD,&GPIO_InitStruct);
}
//LED显示
//入口参数:ucLed-8位显示控制,1-亮,0-灭
void LED_Disp(unsigned char ucLed)
{
GPIO_Write(GPIOC,~ucLed << 8); //疑问?
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //疑问??
}
//蜂鸣器接口初始化
void BUZ_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//使能AFIO和GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//配置引脚映射(禁止JTRST功能)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE); //疑问???
//PB4推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
简要分析:❤️
- 初始化GPIO的顺序,①声明GPIO结构体变量→②使能端口时钟→③配置引脚Pin,速度Speed,模式Mode→④调用Init函数初始化结构体;
- 解迷①:因为开发板的8个LED指示灯LED1 ~ LED8通过锁存器与PC8~PC15相连,低电平时LED亮,高电平LED灭(根据原理图判断),所以显示控制时使用GPIO_Write函数把位左移8位到PC8;
- 解迷②:锁存器的使能端与PD2相连,低电平时锁存数据(锁存器输出不随输入变化),高电平时不锁存数据(锁存器输出随输入变化),所以会给PD2设置高低电平。
- 解迷③:PB4位什么不能和LED一样初始化引脚,还需要配置映射?因为PB2的复位功能为JTRST(JTAG复位),不是普通的GPIO的功能,所以需要GPIO_PinRemapConfig()禁用JTRST功能,而调用这个函数需要打开AFIO时钟才能正常GPIO输出配置操作,也时低电平打开蜂鸣器。
三、实现功能过程的注意与学习点
1、注意点
- 通过芯片数据手册查看各个引脚复位的功能,防止初始化不成功。
- 根据开发板原理图可知开发板是高电平或低电平点亮或者打开蜂鸣器。
- char类型占用1个字节,左移超出8位后数据溢出重新等于0
2、学习的知识点
- 初始化GPIO的顺序:①声明GPIO结构体变量→②使能端口时钟→③配置引脚Pin,速度Speed,模式Mode→④调用Init函数初始化结构体;
- 使能AFIO时钟,用GPIO_PinRemapConfig()禁用JTRST功能
- GPIO有4种输入模式,4种输出模式,共8种GPIO模式。分别为浮空输入_IN_FLOATING、模拟输入_AIN、上拉输入_IPU、下拉输入_IPD输入模式,以及推挽输出_OUT_PP、开漏输出_OUT_OD、推挽复用输出_AF_PP、开漏复用输出_AF_OD输出模式,详解可参考GPIO的8种工作模式详解
❤️ ❤️ ❤️ ❤️ ❤️ ❤️