STC51(点灯+五向开关)
实物
原理图
丝印层
这个实验需要做程序的烧录,需要一些下载的软件什么的
https://www.stcisp.com/
STC的官网丢上来。
菊花里面夹芯片
哪个鬼才整的这花活
好家伙儿,我一往开点。差点把我送走
这是
吃~
这个是意法的官网,不是我崇洋媚外。
芯片这么高大上的东西,能不能让我看一眼就不明觉厉啊。。。
点击这里下载烧录软件
http://www.stcmcudata.com/STCISP/stc-isp-15xx-v6.88.zip
解压的文件有这些
打开以后第一遍提醒这个
说我芯片老,emmmmm
先设置一下这个串口
按说是先点灯才对,我们点个灯吧
这个就是编程控制的最基本的
这个地方的意思就是连接串口烧录
P3.0
P3.1
在这个地方可以知道设计的准则
选择晶振的频率
选择要生成hax文件
我们还要加这个头文件,延时用
选择要下载的Hax文件
上传成功
#include "reg52.h"
#include "intrins.h"
sbit LED = P1^7;
void Delay1000us();
int main(void){
while(1){
LED = 0;
Delay1000us();
LED = 1;
Delay1000us();
}
}
void Delay1000us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
对于这个延时,可以用下载软件的自动生成代码
到现在为止,灯也亮完了。硬件ok,软件ok~
写按钮吧~
我们一会儿写程序实现这个效果
上下左右,这个叫法顺口
对应小灯LED1,2,3,4
看到对应连接4个LED小灯
左边还有限流电阻
这个是原理图,是公阳极的连接
分别连在芯片这些脚上
我们要实现以上的功能,需要这么多的文件。或者说是程序
我边写边解释嗷~
按照我上篇文章的说法
这个程序分为,硬件模块,逻辑模块以及延时模块
#include "config.h"//ÒýÈëÅäÖÃÄ£¿é
#include "key.h"//ÒýÈ밴ťģ¿é
#include "delay.h"//ÒýÈëÑÓʱģ¿é
int main(void){
while(1){
if(!Key_Up_Press())led1=~led1; //up -> led1 toggle
if(!Key_Left_Press())led2=~led2; //left -> led2 toggle
if(!Key_Right_Press())led3=~led3; //right -> led3 toggle
if(!Key_Down_Press())led4=~led4; //down -> led4 toggle
if(!Key_Enter_Press()){ //enter -> led1~led4 toggle
led1=~led1;
led2=~led2;
led3=~led3;
led4=~led4;
}
}
}
上面的编码方式有点不对劲,是GB2312的。浏览器是UTF-8的,所以乱码了
这个地方我注释都是加的模块,可能更加的符合程序整体的模块化的感觉
可能有人会问为什么木有看见单片机特殊功能寄存器的头文件,那是因为在配置文件的模块里面引用了,属于配置方面的模块了,注意这种编程的思想
while(1){
if(!Key_Up_Press())led1=~led1; //up -> led1 toggle
if(!Key_Left_Press())led2=~led2; //left -> led2 toggle
if(!Key_Right_Press())led3=~led3; //right -> led3 toggle
if(!Key_Down_Press())led4=~led4; //down -> led4 toggle
if(!Key_Enter_Press()){ //enter -> led1~led4 toggle
led1=~led1;
led2=~led2;
led3=~led3;
led4=~led4;
}
}
因为就是裸机的MCU编码,所以直接死循环安排了
下面写了5个if判断,来判断对应按钮按下灯的状态!我用了状态的词语
这个里面的要点有很多:
比如文件的格式,这个是一种写法
while (1)
{
if (!Key_Up_Press())
{
led1 = ~led1
}; //up -> led1 toggle
if (!Key_Left_Press())
{
led2 = ~led2
}; //left -> led2 toggle
if (!Key_Right_Press())
{
led3 = ~led3
}; //right -> led3 toggle
if (!Key_Down_Press())
{
led4 = ~led4
}; //down -> led4 toggle
if (!Key_Enter_Press())
{ //enter -> led1~led4 toggle
led1 = ~led1;
led2 = ~led2;
led3 = ~led3;
led4 = ~led4;
}
}
我可以写成这样
有的人习惯上是如果if后面只有一个语句,就直接分号处理。
我给的建议是,只要出现if就加{},这是一种习惯。分号的作用就是来限定作用域,不能因为代码量少就破坏这种感觉,诚然单语句不写花括号是清爽的表现,但是现代软件工程就难在维护上面。希望你要了解这些代码之外的东西,在编写之初,甚至是学习之初就不要有小毛病。
还有这个变量名的命名方式单个动词大写首字母用多个下划线连接多个动词。
还有一点就是用~的逻辑运算符号
if (!Key_Enter_Press())
{ //enter -> led1~led4 toggle
led1 = ~led1;
led2 = ~led2;
led3 = ~led3;
led4 = ~led4;
}
最后直接就是按下中心按钮,4个LED同时取反。
接下来我们看我们对按钮模块的抽象
首先看h文件,对将要使用的函数有个认识
可以从这几个方面看
那我们上面的函数就是,无参数调用。返回值是个bit。
其实就是返回一个状态
这个文件就是key的实现了
首先是引入3个头文件,具体作用可以看上面。头文件让模块之间相联系
首先这个C文件里面就是5个函数的具体实现。没有其他内容
bit Key_Up_Press(void){
bit flag = 1; //¶¨Òå°´¼ü±ê־λ
key1 = 1; //ÉèÖóÉÊäÈë״̬
if(!key1){ //²éѯ°´¼üÊÇ·ñ°´ÏÂ
Delay15ms(); //Ìø¹ýÇ°Ñض¶¶¯
if(!key1){ //È·¶¨ÊÇ·ñ°´ÏÂ
while(!key1); //µÈ´ýÊÍ·Å
Delay15ms(); //Ìø¹ýºóÑض¶¶¯
while(!key1); //µÈ´ýÊÍ·Å
flag = 0; //°´¼ü±ê־λÇåÁã
}
}
return flag; //·µ»Ø0±íʾ°´¼ü°´ÏÂ
}
就分析一个函数就可以,其他函数都是改一下名字而已
此时我们遇到了第一个难点
你认为你按下这个开关的时候电路一下机导通了,并且维持在稳定的状态。其实不是的,这个过程里面有机械抖动的,按下时的抖动叫前沿抖动,中间才是稳定的状态。你抬手的时候,是按下的逆向过程。
对于按钮你想实现很多的功能,比如摁一下,俩下,三下,长按1s,长按2s。这些场景里面,上面的这个物理现象就会让你很苦恼,怎么办?
在制作很昂贵的硬件的时候,或者你的客户一定要加硬件去抖动的
亦或是你真的很富有,那你就加。(其实按键俩段并联电容就好)
我们重点讲这个软件去抖动。
延时+判断就好了,既然抖动过程很短,那就避过去,然后再判断你的按键情况。
就好了,至于这个延时时间目前是15ms(单片机是us运行)。
这个就是我们编写这个程序的依据
首先定义了一个bit变量,来存放一个默认的状态,这个bit未来会传出去。
接着将IO设置为输入的状态,一接通,导电,开始干活
接着是一个if的判断,先查看IO的信息,确认没有按下!
开始软件延时:延时15ms
再if判断,查看此时的IO状态,如果按下的话就等着按键的下个状态就是松开。此时再延时来跳过松开按键时,IO对按钮状态的读取。释放了,按钮的状态就是0,所以flag = 0;接着跳出循环,用return将按键的信息传递出去。函数的使命就结束了。当然更加复杂的逻辑也是这个函数的变种,我们后面会分析一个游戏手柄的库,我们再详细的进行分析。
这个是上文对应的查询方式
延时函数的头,一个15ms,一个5ms
这个是具体的实现,可以用软件生成
在配置文件内,首先是两个头文件
一个是MCU的特殊功能寄存器的定义或是映射表
一个是延时用的头文件
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
typedef signed char int8;
typedef signed int int16;
typedef signed long int32;
typedef是一个内置的关键字(我在放屁),就是将已有的数据类型重新包装(就是对于名字而已),优点是统一数据类型,方便多平台移植。
然后就是一个对于引脚的定义
就是这么个情况,视频还得审核、、、