任务一:debug控制单个LED
任务要求
-
在debug模式下控制LED的亮灭。
图片展示
实现思路
使用库函数控制led灯的亮灭,RCC_APB2PeriphClockCmd函数用于控制APB2的外设时钟(时钟默认关闭),这里用它来开启GPIOC的外设时钟;GPIO_Init函数用于配置端口模式,初始化GPIO;GPIO_SetBits(GPIOC, GPIO_Pin_13)可将GPIO_Pin_13配置为高电平;相应的,GPIO_ResetBits(GPIOC, GPIO_Pin_13)将端口配置为低电平。
CTRL+F查找字符位置,CTRL+ALT+space调出软件建议,建议可用tab键选中.
关键代码
#include "stm32f10x.h" // Device header
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
// GPIO_ResetBits(GPIOC, GPIO_Pin_13);
while(1)
{
}
}
任务二:实现流水灯
任务要求
-
通过固件库函数实现GPIO控制单个LED亮灭。
-
实现多个LED有序亮灭完成流水灯。
视频展示
实现思路
GPIO_Write调用端口,通过delay函数实现led灯依次点亮
关键代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
while (1)
{
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_ms(100);
}
}
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
任务三:按键控制流水灯开启与关闭
任务要求
-
按下按键能够启动流水灯,再按下按键能够停止流水灯。
-
当前程序有什么问题吗?
视频展示
实现思路
沿用之前的流水灯程序,将流水灯开启封装在代码LED_ON之中,调用GPIO_ReadInputDataBit函数读取GPIO输入
key函数端口要用上拉输入配置
关键代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
uint8_t KeyNum;
int main(void)
{
LED_Init();
Key_Init();
while(1)
{
KeyNum = Key_GetNum();
if(KeyNum == 1)
{
LED_ON();
}
}
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_All);
}
void LED_ON(void)
{
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_ms(100);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_ms(100);
GPIO_SetBits(GPIOA,GPIO_Pin_All);
}
void LED_OFF(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_All);
}
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0);
Delay_ms(20);
KeyNum= 1;
}
return KeyNum;
}
进阶任务:随机流水灯
任务要求
-
使得每次复位板子后,按下按键后流水灯的顺序随机。
视频展示
//如果需要,请在此处插入视频
实现思路
//这一流水灯是通过for循环延时的,在主函数里……
关键代码
#include "global.h"
……
#include "bsp_led.h"
……
//以下是学习时的记录
STM32的GPIO
1. GPIO的种类
STM32F103C8T6共有2组IO口,每组16个,共16×2=32个,分别为:
GPIOA——>PA0、PA1、PA2…PA15
GPIOB——>PB0、PB1、PB2…PB15
2. GPIO的基本结构
每个GPIO内部都有这样的一个电路结构,如图
3. GPIO输入输出的8种模式
程序中标识 | 模式 |
GPIO_Mode_AIN | 模拟输入 |
GPIO_Mode_IN_FLOATING | 浮空输入 |
GPIO_Mode_IPD | 下拉输入 |
GPIO_Mode_IPU | 上拉输入 |
GPIO_Mode_Out_OD | 开漏输出 |
GPIO_Mode_Out_PP | 推挽输出 |
GPIO_Mode_AF_OD | 复用开漏输出 |
GPIO_Mode_AF_PP | 复用推挽输出 |
4. GPIO各模式的使用场景
1 GPIO_Mode_AIN:模拟输入
一般用于ADC模拟输入
2 GPIO_Mode_IN_FLOATING:浮空输入
在外部触发时经常用到……
3 GPIO_Mode_IPD和GPIO_Mode_IPU:下拉输入和上拉输入
这个模式下接入了GPIO内部的上下拉电阻,上下拉电阻的阻值是……
可以看到KEY_UP按下后,IO口应该是3V3电平输入,未按下时为悬空状态,而悬空状态IO输入是未知的,所以为了防止程序跑飞,采用下拉输入,在悬空状态下,使IO输入下拉到低电平。这样,在悬空状态下,IO检测到的是低电平,不会去执行key_up按下后的程序。