历史上的今天
返回首页

历史上的今天

今天是:2025年05月31日(星期六)

2019年05月31日 | STM32掌机教程3,工程模板与带灯按键测试

2019-05-31 来源:eefocus

我们需要“脚手架”

  关于代码,我想体现出这么一个过程:我是如何一步一步修改代码的。我认为,从学习的角度来考虑,直接看最终的代码没有什么意义。 写代码就像工人盖房子,盖房子过程中,工人要搭建脚手架;房子盖好以后,脚手架要拆除。直接领着学生看盖好的房子,说,你就照着这个样子来盖房子,学生是做不出来。他不知道怎么搭建脚手架,甚至都不知道什么是脚手架。 所以我打算这个系列的讲义,每一篇代码都在上一篇的基础上做一些改进,保留代码“进化”的过程。有些过程代码在最终的代码中不会体现,但是也很重要,就像房子盖好以后,你看不到脚手架一样。我们需要脚手架。

在这里插入图片描述

  目前用到的代码先用压缩包的形式上传,等教程写完以后,后续代码的维护使用Git。


各种初始化

  下载压缩包并打开工程以后,可以在main.c里找到主函数。目前为止,主函数进行了一些初始化,死循环内什么都没写,后续可以根据我们的需要写业务逻辑代码。


//main.c

int main(void)

{

LED_Init();

KEY_Init();

delay_init();

initIIC();

initOLED();

while(1)

{



}

}


LED与SLED的初始化

  函数的作用从名字就可以看出来,比较简单。例如LED的初始化。需要初始化哪个引脚,可以从电路图中看出。


在这里插入图片描述

//IO.c

void LED_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5; 

GPIO_Init(GPIOC, &GPIO_InitStructure);


AllLED_ON();

LED1 = LED_ON;

LED2 = LED_OFF;

}



  具体LED或者SLED对应的引脚可以在原理图中看出来。为了方便使用,我根据外设与引脚关系做了宏定义。


//IO.h

#define SLED1 PCout(0)

#define SLED2 PCout(1)

#define SLED3 PCout(2)

#define SLED4 PCout(3)

#define LED1 PCout(4)

#define LED2 PCout(5)

#define SLED5 PBout(12)

#define SLED6 PBout(13)

#define SLED7 PBout(14)

#define SLED8 PBout(15)

#define SKEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)

#define SKEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)

#define SKEY3 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)

#define SKEY4 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)

#define SKEY5 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_6)

#define SKEY6 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_7)

#define SKEY7 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_8)

#define SKEY8 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_9)


#define PAUSE GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)

#define BEEP PBout(1)


#define KEY1_PRES    1    //KEY1按下

#define KEY2_PRES    2    //KEY2按下

#define KEY3_PRES    3    //KEY3按下

#define KEY4_PRES    4    //KEY4按下

#define KEY5_PRES    5    //KEY5按下

#define KEY6_PRES    6    //KEY6按下

#define KEY7_PRES    7    //KEY7按下

#define KEY8_PRES    8    //KEY8按下

#define PAUSE_PRES   9


#define LED_ON  0

#define LED_OFF 1

#define DOWN  0 //按键按下

#define FREE  1


  然后编写了两个函数,用于点亮所有LED或者关闭所有LED


//IO.c

void AllLED_ON(void)

{

GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);

}

void AllLED_OFF(void)

{

GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);

}


  这些代码。可能对于某些没有使用过STM32的同学来说不太好看懂,不过没有关系,可以仅仅应用的话,这是很简单的。在我之前的博客里也提过一些库函数的基础。例如设置某引脚为推挽输出GPIO_Mode_Out_PP ,不知道什么事推挽输出可以自己查一下。设置哪个引脚为推挽输出?PB12到PB15,PC0到PC5。

  再比如,让某个LED亮起来GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);很容易看出来,这个操作是把PB12到PB15置为低电平,结合原理图可知,引脚低电平可以点亮LED。


按键初始化与扫描函数

  按键设置为上拉输入,检测到低电平,说明按键被按下。按键扫描函数课可以返回被按下的按键值。


void KEY_Init(void)  //PB0-PB3

{

GPIO_InitTypeDef GPIO_InitStructure;


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/*

//PB3与PB4默认用作调试口,如果用作普通的IO,需要加上以下两句 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入

GPIO_Init(GPIOA, &GPIO_InitStructure);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 

GPIO_Init(GPIOB, &GPIO_InitStructure);


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; 

GPIO_Init(GPIOC, &GPIO_InitStructure);

  

}

unsigned char KEY_Scan(unsigned char mode)

{    

static u8 key_up=1;//按键按松开标志

if(mode)key_up=1;  //支持连按          

if(key_up&&(SKEY1==DOWN||SKEY2==DOWN||SKEY3==DOWN||SKEY4==DOWN||SKEY5==DOWN||SKEY6==DOWN||SKEY7==DOWN||SKEY8==DOWN||PAUSE==DOWN))

{

delay_ms(10);//去抖动

key_up=0;

if(PAUSE==DOWN)return PAUSE_PRES;

else if(SKEY1==DOWN)return KEY1_PRES;

else if(SKEY2==DOWN)return KEY2_PRES;

else if(SKEY3==DOWN)return KEY3_PRES;

else if(SKEY4==DOWN)return KEY4_PRES;

else if(SKEY5==DOWN)return KEY5_PRES;

else if(SKEY6==DOWN)return KEY6_PRES;

else if(SKEY7==DOWN)return KEY7_PRES;

else if(SKEY8==DOWN)return KEY8_PRES;

}else if(SKEY1==FREE && SKEY2==FREE && SKEY3==FREE && SKEY4==FREE && SKEY5==FREE && SKEY6==FREE && SKEY7==FREE && SKEY8==FREE && PAUSE==FREE)key_up=1;         

return 0;// 无按键按下

}


其它初始化

  延时函数的初始化借用了别人的代码,就不贴了。

  0.96OLED屏幕用到了IIC总线,所以既需要初始化IIC总线,也需要初始化OLED屏幕。其实初始化的代码也不是我写的,借用的。有的读者可能会说,屏幕的初始化好像挺难的,我不知道这些初始化函数怎么写出来。这个问题很好解决——如果厂家不提供初始化的代码,我们不买它的屏幕就行了。谁提供代码,提供技术支持,我们选谁的屏幕。毕竟


  另外,对于定时器和蜂鸣器,我也写好了初始化代码。用到再说吧。


带灯按键检测

  在LED的初始化函数中,已经点亮了所有的带灯按键。如果按键上的灯不亮,就只能找硬件问题了。接下来写一小段测试代码,判断按键按下能否检测到。

  我的思路是,如果按下了某个按键,那么按键对应的LED灯状态翻转。STM32中,让引脚状态翻转其实是比较高阶的操作,原理比较复杂,感兴趣的可以搜下STM32的位带操作。但是用起来很简单,把寄存器当数据操作,假装寄存器可以取反。例如,LED1的状态取反LED1 = !LED1,如此操作,可以不用关心LED之前是亮是灭,看到的现象就是状态变了。

  我们可以写一个switch case语句,根据按键值来操作对应的LED。


while(1)

{

switch(KEY_Scan(0))

{

case PAUSE_PRES:

LED1 = !LED1;

LED2 = !LED2;

break;

case KEY1_PRES:

SLED1 = !SLED1;

break;

case KEY2_PRES:

SLED2 = !SLED2;

break;

case KEY3_PRES:

SLED3 = !SLED3;

break;

case KEY4_PRES:

SLED4 = !SLED4;

break;

case KEY5_PRES:

SLED5 = !SLED5;

break;

case KEY6_PRES:

SLED6 = !SLED6;

break;

case KEY7_PRES:

SLED7 = !SLED7;

break;

case KEY8_PRES:

SLED8 = !SLED8;

break;

default:

break;

}

}


  现象就是,上电以后,所有的按键灯都亮,如果按下某个按键,那么按键对应的灯状态翻转。



推荐阅读

史海拾趣

HBControls公司的发展小趣事
如果压缩机工作但冰箱不制冷,可能是制冷剂不足或泄漏。这需要专业人员进行检查和补充或更换制冷剂。
Cableform Inc公司的发展小趣事

随着技术的不断进步和市场的扩大,Cableform Inc公司意识到必须走出国门,开拓更广阔的市场。1974年,公司在弗吉尼亚州特洛伊成立了北美业务分部,这是公司国际化战略的重要一步。在北美市场,公司面临着激烈的竞争和不同的文化背景,但凭借着优质的产品和服务,Cableform Inc逐渐赢得了客户的信任,市场份额稳步上升。

全鹏(CHAMPION)公司的发展小趣事

为了提升国际市场竞争力,全鹏公司一直致力于提高产品质量和管理水平。在2014年,全鹏电子科技有限公司成立,并成功通过了ISO9001国际质量管理体系、ISO14001环境管理体系认证和汽车与医疗器材体系IATF/16949认证。这些认证不仅证明了全鹏公司在质量管理方面的实力,也为其在国际市场上赢得了更多的信任和机会。

远阳(FLYOUNG)公司的发展小趣事

国光新业深知技术创新是企业发展的核心动力。截至目前,公司已拥有授权专利78项,其中发明专利30项,实用新型专利48项,还有数十项专利正在实质审查中。这些专利的积累,不仅彰显了公司在电容器领域的深厚技术底蕴,更为公司产品的持续升级与市场竞争力的提升提供了有力保障。公司还主导起草了两项该类高分子电容器国家标准,进一步巩固了其在行业内的领先地位。

Festo公司的发展小趣事

Festo公司成立于1925年,由Albert Fezer和Gottlieb Stoll两位创始人共同创立。最初,公司专注于木工机械和木工工具的生产,其品牌Festool在行业内享有盛誉。凭借对工艺的精湛掌握和对品质的严格把控,Festo迅速在木工机械领域崭露头角,为公司的后续发展奠定了坚实的基础。

General Microcircuits Corp公司的发展小趣事
选择低噪声的运算放大器,以提高系统的信噪比。

问答坊 | AI 解惑

[分享]教你怎样在POWER LOGIC里面做BGA封装

要先建CAE decal,再建part type 在建PART type时,只需要将建好的CAE decal调入再编辑pin NUMBER就可以了,就是字母了 建立新part type时,在part information for part面板中,选中gates栏。在这里的右边有一 个add按钮,将刚刚制作的cae type ...…

查看全部问答>

选择什么样的arm9开发版来入门?

大家好,小弟有m3的开发经验,现在想进军arm9领域,感觉应该是买2440吧,无奈市面上2440的开发板比那璀灿的繁星还要多。。。所以呢,想请教一下各位大侠,究竟哪一款的2440开发板比较适合入门者,性价比右比较高的呢??…

查看全部问答>

verilog

WARNING:Xst:1895 -Due to other FF/Latch trimming, FF/Latch   (without init value) has a constant value of 0 in block .这样的警告对程序有何影响,怎样改? …

查看全部问答>

大家好,新人报个到.........

辛辛苦苦自学了三四个月,终于找到工作了........ 以后还请大家多多指教.....谢谢!…

查看全部问答>

主从轴跟随不能一致同步的问题?

PLC控制两台伺服电机工作:主轴做固定的圆周运动,要求从轴跟随主轴在一定的距离内(2MM左右)做循环正反转(两台伺服电机的加减速时间设各一致),我现在在实际的应用中困惑的是:主轴在经过加减速时间就能达设定的转速,并且恒速保持下去直到停止 ...…

查看全部问答>

ARM7新手求教

我想学ARM,从老师那里拿了个博创的UP-NETARM3000实验箱,老师说先把ADS的程序移植过来实现效果了再说。自己弄了好几天了,就是不会。我看了好多教学,都是新建工程后还要加几个组,之前学过单片机,只有一个组的,这里有lib,code等等,而且每个教 ...…

查看全部问答>

求教可编程压力传感器的调理补偿(标定)过程

请问可编程压力传感器的调理补偿是如何进行的呢?(如MLX90807)待测传感器需要放进容器里面进行调理补偿么(在容器里进行压力和温度的改变)?还是直接用一个普通传感器放到容器里找到几个点,将值输到软件里进行调理补偿(待测传感器放在外面的? ...…

查看全部问答>

ARM语法问题

#define   LED_ADJ         16#define   LED_IOCON         (0xFF<<LED_ADJ)#define   LED_OFF()      ...…

查看全部问答>

STM32新手之新建工程二

首先创建项目目录,拷贝公共文件:将 STM32 软件库中 FWlib 目录中的 library 目录拷贝到所建项目的目录中 下载 (17.23 KB)2008-10-21 15:51这个是库 FWLIB 文件夹 把 FWlib 目录中的 library 目录拷贝到所建项目的目录中 下载 (18.94 K ...…

查看全部问答>