实验1:点亮LED
实验2:按键控制LED
实验3:外部中断检测按键
实验4:扩展芯片检测按键
实验5:定时器实现LED闪烁
实验6:基于PWM的呼吸灯
实验7:检测输入的PWM频率和脉宽
实验8:串口的输入和输出
实验9:串口使用PRINTF函数
实验10:SPI接口操作片外FLASH
实验11:SPI接口操作TF卡
实验12:IIC接口操作OLED屏幕
实验13:ADC电压采样
实际应用过程中,经常会遇到按键过多,GPIO不够用的情况。这时我们需要通过外部芯片来对按键检测功能进行扩展。方式有很多,这里使用的是74HC165芯片,仅用3个IO即可检测8、16、32..甚至100多个按键。
74HC165检测按键的电路如下:
连接到单片机上的接口如下,分别是PB0、PB1、PB2:
接下来打开STM32CUBEMX,进行相应操作:
1、新建工程,进行基本配置。通过点击“ACCESS TO MCU SELECTOR”来创建一个新的工程:
参照实验1,芯片选择“STM32F103C8”。
打开外部时钟,点击“System Core”,选择RCC,在右侧弹出的菜单栏中选择“Crystal/Ceramic Resonator”。
选择调试接口,点击“System Core”,选择RCC。,在右侧弹出的菜单栏中选择“Serial Wire”。
2、LED的IO配置。依然使用PC15、PA1、PA2,参照实验1,依次对这三个管脚进行配置(输出模式),分别命名为D1、D2、D3。
3、74HC165的相关IO配置。该芯片的使用需要用到三个IO,这里用STM32的PB0PB1PB2来进行驱动。
PB0配置为输出模式,命名为:HC165_SH
PB1配置为输出模式,命名为:HC165_CLK
PB2配置为输入模式,命名为:HC165_DS
同时,在GPIO页面,确保PB0和PB1的初始值为低电平,PB2的上拉电阻打开。如下:
4、时钟配置。参照实验1.
5、生成工程。参照实验1的步骤7,进行相应配置,生成工程文件。
6、修改工程-添加74HC165驱动程序。驱动程序为网友在网上分享,这里演示下如何添加到工程中。
先把包含74HC165驱动程序的文件夹,复制、粘贴到指定位置。这里我们选择该路径:USB04KEYSER\Drivers\CMSIS\Device,如图:
然后打开工程,如图,点击“Option for Target”按钮,选择“C/C++”选项卡,点击“Include Paths”后面的按钮。
在弹出的页面中,点击位置1,为当前工程添加一个新的驱动程序路径;点击位置2,选择刚才我们粘贴的文件夹。注意是文件夹,不是文件,因为这里添加的是路径。
我这里已经添加好了,然后直接点击OK即可。
接下来,如下鼠标右键点击“Application/User/Core”,在弹出的对话框里选择“Add Existing Files to Group ‘Application/User/Core’..”
在弹出的对话框中,选择刚才粘贴的文件夹中的“hc165.c”文件,然后依次点击”Add”、“Close”即可。
这是,该文件会出现在左侧的工程栏里,如下:
7、修改工程-调用74HC165驱动程序。
先确保IO相关的宏定义,在hc165.h中:
#ifndef __HC165_H
#define __HC165_H
//#include "stm32f0xx.h"
//#include "systick_delay.h"
//#include "main.h"
#include "gpio.h"
#define CLK_L HAL_GPIO_WritePin(HC165_CLK_GPIO_Port, HC165_CLK_Pin, GPIO_PIN_RESET)
#define CLK_H HAL_GPIO_WritePin(HC165_CLK_GPIO_Port, HC165_CLK_Pin, GPIO_PIN_SET)
#define SL_L HAL_GPIO_WritePin(HC165_SH_GPIO_Port, HC165_SH_Pin, GPIO_PIN_RESET)
#define SL_H HAL_GPIO_WritePin(HC165_SH_GPIO_Port, HC165_SH_Pin, GPIO_PIN_SET)
#define DAT HAL_GPIO_ReadPin(HC165_DS_GPIO_Port, HC165_DS_Pin)
void HC165_PIN_INIT(void);
uint8_t ReadByte_165(void);
#endif
然后在main.c中,定义一个变量,用来存储读取到的按键状态:
接下来,在main.c中添加一段代码,用来实现us级别的延时:
/* USER CODE BEGIN 0 */
typedef uint8_t u8;
typedef uint32_t u32;
u8 fac_us;
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS
u32 reload;
#endif
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
//SysTick HCLK
fac_us=SYSCLK; // OS,fac_us
#if SYSTEM_SUPPORT_OS // OS.
reload=SYSCLK;
reload*=1000000/delay_ostickspersec; //delay_ostickspersec
//reload 24Bit 16777216, 180M 0.745s
fac_ms=1000/delay_ostickspersec; // OS.
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;// SYSTICK
SysTick->LOAD=reload; // 1/OS_TICKS_PER_SEC
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; // SYSTICK
#else
#endif
}
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD
ticks=nus*fac_us;
told=SysTick->VAL;
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; // SYSTICK.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break;
}
}
}
要使该延时生效,需要在初始化阶段调用延时初始化函数:
最后,在while(1)主循环里添加调用74HC165读取外部按键状态的函数,并做出处理:
key_value = ReadByte_165();
if(key_value != 0xff)
{
if(key_value == 0xfe)
{
HAL_GPIO_TogglePin(D1_GPIO_Port,D1_Pin);
}
else if(key_value == 0xfd)
{
HAL_GPIO_TogglePin(D2_GPIO_Port,D2_Pin);
}
else if(key_value == 0xfb)
{
HAL_GPIO_TogglePin(D3_GPIO_Port,D3_Pin);
}
HAL_Delay(10);
while(0xff != ReadByte_165());
}
位置如下:
修改后,保存,编译、下载,重新上电。KUP、KDOWN、K_LEFT这三个按键,每按一下按键,对应LED的状态翻转一次。
整个过程有PPT、数据手册、原理图、源码、相关软件,在公众号(单片机爱好者)回复关键词:002或者STM32CUBEMX教程,即可获取下载链接。
002
不是这里哦,是公众号