任务一:按键控制定时流水灯
任务要求
-
通过Systick实现流水灯频率控制,要求循环一次流水灯耗时1s。
-
使用外部中断功能,用按键控制流水灯。按下按键一开启流水灯,再按下按键一关闭流水灯,按下按键二暂停流水灯。
实现思路
为了实现同一个按键控制开启关闭的功能,用exti监测按键按下次数,return CountSensor_Count返回按下按键数量,并在OLED上显示(便于调试);在返回值为奇数时开启流水灯,偶数时关闭流水灯.
视频展示
关键代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "EXTI.h"
#include "LED.h"
int main(void)
{
CountSensor_Init();
LED_Init();
OLED_Init();
OLED_ShowString(1,1,"Count:");
GPIO_SetBits(GPIOA,GPIO_Pin_All);
while(1)
{
OLED_ShowNum(1,7,CountSensor_Get(),5);
OLED_ShowNum(2,7,Countting_Get(),5);
uint16_t key_count = CountSensor_Get();
int16_t key_Countting = Countting_Get();
if((key_Countting+1)%2==0){
if((key_count+1)%2==0)
{
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);
}
}
else {
GPIO_SetBits(GPIOA,GPIO_Pin_All);
}
}
}
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;
void CountSensor_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置GPIO
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);
//配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource11);
//配置EXTI
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line11;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
//下降沿触发,按实际需求
EXTI_Init(&EXTI_InitStruct);
//配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//根据实际
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
}
uint16_t CountSensor_Get(void)
{
return CountSensor_Count;
}
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line11)== SET)
{
CountSensor_Count ++;
EXTI_ClearITPendingBit(EXTI_Line11);
}
}
//.h
#ifndef _BSP_SYSTICK_H
#define _BSP_SYSTICK_H
#include "stm32f10x.h"
#include "core_cm3.h"
void systick_delay_us(uint32_t us);
void systick_delay_ms(uint32_t ms);
#endif /*_BSP_SYSTICK_H*/
//.c
#include "stm32f10x.h"
#include "bsp_systick.h"
#include "core_cm3.h"
void systick_delay_us(uint32_t us)
{
SysTick_Config(72);
uint32_t i;
for(i=0;i<us;i++)
{
while(!((SysTick->CTRL)&1<<16));
}
//当结束计时的时候,我们要关掉计时器,把它的使能关掉~取反
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
void systick_delay_ms(uint32_t ms)
{
SysTick_Config(72000);
uint32_t i;
for(i=0;i<ms;i++)
{
while(!((SysTick->CTRL)&1<<16));
}
//当结束计时的时候,我们要关掉计时器,把它的使能关掉~取反
SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}
任务二:阅读手册
任务要求
-
了解参考手册和数据手册的区别和联系
-
找到 GPIO 的功能框图,知道哪部分是 GPIO 输出、GPIO 输入、外设复用功能,并将 GPIO 的各种模式和它们联系起来
-
找到系统时钟树,简单介绍各部分的挂载
参考手册和数据手册的区别和联系
区别:
内容:参考手册主要提供了STM32微控制器的整体架构、功能模块、时钟配置、引脚定义、寄存器描述等方面的信息。数据手册则更加详细地描述了每个功能模块的工作原理、寄存器的位定义、时序要求、电气特性等技术细节。
用途:参考手册主要用于整体了解STM32微控制器的特性和功能,为系统设计提供指导。数据手册则更多地用于硬件和软件开发工程师进行具体的设计、编程和调试。
联系:
信息补充:参考手册和数据手册通常是相互关联的。参考手册提供了STM32微控制器的总体架构和功能描述,而数据手册提供了更为详细的技术细节。两者合起来可以提供全面的信息,帮助开发人员更好地理解和应用STM32微控制器。
相互引用:参考手册中通常会引用数据手册中的相关章节和内容,以便读者可以在需要更深入了解的时候去查阅数据手册。
GPIO 的功能框图
GPIO输入输出的8种模式
程序中标识 | 模式 | 介绍 |
GPIO_Mode_AIN | 模拟输入 | 连接模拟输入 |
GPIO_Mode_IN_FLOATING | 浮空输入 | 不连接电阻 |
GPIO_Mode_IPD | 下拉输入 | 连接到下电阻Vss |
GPIO_Mode_IPU | 上拉输入 | 连接到上电阻VDD |
GPIO_Mode_Out_OD | 开漏输出 | N-MOS控制,只能输出低电平,可配合外部电流使用 |
GPIO_Mode_Out_PP | 推挽输出 | P-MOS和N-MOS同时控制,可输出3.3V高电平和低电平 |
GPIO_Mode_AF_OD | 复用开漏输出 | 由复用功能输出控制,如定时器控制GPIO |
GPIO_Mode_AF_PP | 复用推挽输出 | 由复用功能输出控制 |
系统时钟树
时钟信号能够防止逻辑门判断波动,只有当方波的上升信号到达边沿触发器时才会写入寄存器,故运行前必须先打开时钟,时钟对程序的运行至关重要。由时钟源产生方波信号,又由时钟树传递到芯片的各个地方。
HSE时钟:高速外部时钟
LSE时钟:高速内部时钟
sysclk时钟:系统时钟
任务三:debug控制单个LED
任务要求
-
进入 Debug 模式,了解 复位,四种运行(单步,全速等),断点,Watch 窗口的使用
-
在debug模式下控制LED的亮灭(修改寄存器值或变量值)
-
提示:使用 Debug 的断点,Watch,Call Stack + Locals 等功能,分析变量的值和程序运行的流程
Dubug
1. 复位和五种运行模式
从左到右依次:reset,全速运行,停止全速运行,单步运行,跳过当前行单步运行,跳出当前函数单步运行,跳到光标指定行单步运行.
-
reset键:复位键,使程序回到初始位置
-
全速运行:程序会全速运行直到停在设置的断点
-
停止全速运行:顾名思义
-
单步运行:执行黄色光标指示的行
-
跳过当前行单步运行:顾名思义
-
跳出当前函数单步运行:顾名思义
-
跳到光标指定行单步运行:跳到蓝色光标指示行运行
鼠标左键设置断点,右键设置蓝色光标
2. 窗口
从左到右依次:命令窗口(commend),反汇编窗口,符号窗口(symbol),registers,memory,watch
另可以在外设菜单栏的系统资源查看中看到所有寄存器端口的值.
调试模式下不能直接修改程序,需要退出调试模式修改后重新编译
快捷键
通用快捷键
查找 | Ctrl+F |
替换 | Ctrl+H |
全选 | Ctrl+A |
撤销 | Ctrl+Z |
反撤销 | Ctrl+Y |
剪切 | Ctrl+X |
跳转到指定行 | Ctrl+G |
保存文件 | Ctrl+S |
向右缩进 | Tab |
向左缩进 | Shift+Tab |
编译 | F7 |
在线调试 | Ctrl+F5 |
下载 | F8 |
自定义快捷键
keil中的快捷键可以自己设置,以下设置最常用的注释快捷键为例:
1、点击“扳手”
2、点击“Shortcut Keys”,拖动“滚动条”,找到“注释选择”,点击“创建快捷方式” ,按键盘确定自己需要的快捷键,它会自动显示在1框中,点击“OK”,完成设置。设置其他功能的快捷键以此类推。
3、点击“OK”,完成设置。