学习单片机开发——浅尝点灯的快乐
点灯
- 前言
- 开始点灯
- 基本点灯情况
- 原理图的查看
- 正常点灯
- 花式点灯
- 位选锁存器
- 段选锁存器
- 按键交互
- 独立按键
- 矩阵按键
- 总结
前言
因为刚开始学习51单片机,经过同学的推荐,我选了是清翔的单片机,芯片是STC89C52RC;
清翔的视频链接如下
https://www.bilibili.com/video/BV1nt411f7To?p=35&spm_id_from=pageDriver&vd_source=352cf5eb0220bc4e9ed73c26dc3d8be1
单片机的重点就是**“点灯”**,其实就是高低电平通过我们的程序(多用C语言)发生变化,拉高/拉低(1/0)。
开始点灯
基本点灯情况
点灯,我得理解就是在电路中通过芯片改变电路元件两端的电平拉高或者是拉低(1/0),是电路产生电压差,是电路导通(一般情况,外设元件有一段连接单片机芯片,另一端的连接情况要查看电路原理图)
原理图的查看
原理图,顾名思义就是表示电路板上各器件之间连接原理的图表。学习单片机和学硬件电路设计都是要通过分析电路原理图,了解各种电子器件的功能和工作原理,才能得心应手开展工作的。
查看原理图最主要的是看懂网络标号。
网络标号的优点就是可以减少复杂的线路分布,可以更加直观的分析原理图,并且我觉得这样更加有利于C语言模块化开发
正常点灯
学习单片机点灯,最开始的就是点亮第一个LED灯,十分简单,(我用的是清翔的原理图),参考原理图
因为LED灯是连接的是VCC,需要一个低电平(把P1^0 拉低),才能将电路导通。因此
sbit LED1 = P1^0;
void main() //主函数
{LED1 = 0;//点亮P1.0上的LED
}
当然点灯方法不止一种
sbit LED1 = P1^0;
void main() //主函数
{LED1 = ~LED1;;//点亮P1.0上的LED
}
点亮LED灯后,我们可以尝试让LED闪烁。
sbit LED1 = P1^0;
void delay(int n)//延时函数
{unsigned int x,y;for(x = n;x >= 0;x--)for(y = 114;y >= 0; y--);
}
void main() //主函数
{LED1 = 0;//点亮P1.0上的LEDdelay(50);//软件延时 LED1 = 1;//熄灭P1^0上的LED
)
清翔的单片机上有8个LED灯,我们可以通过运用高低电平尝试流水灯的设计了。
#include<reg52.h>
#include<intrins.h>
void delay(uint z)
{uint x,y;for(x = z; x > 0; x--)for(y = 114; y > 0 ; y--); //晶振11.0592us
} void main ()
{LED = 0xFE;//1111 1110 初值LED1亮P1 = LED;delay(100);//毫秒级延时 100毫秒while(1){LED = _crol_(LED,1);//循环左移,需要预定义intrinsP1 = LED;//移位完成后赋值给P1 每个一个灯点亮delay(100);//毫秒级延时 100毫秒}
}
至此最基本的的点灯就是这样,其中注意P1口,因为单片机上用了8个LED灯,8个LED灯分别连接在89c52芯片中P1口的P10~P17;所以我们可以直接通过8位2进制(或者0x_2位16进制)同时让LED灯直接点亮,这既是并行传输。
明白了并行传输我们就可以搞一搞花式点灯——点亮数码管
花式点灯
点亮数码管之前,我们需要了解一下数码管锁存器74HC573(我用的是清翔单片机外设锁存器)。
- OE: Output Enable 输出使能端
- LE: Latch Enable 锁存器使能端
- D 0 ~ D 7:数据的输入引脚
- Q 0~Q 7:数据的输出引脚
- GND:地线接地端
- VCC:供电电压
位选锁存器
位选,顾名思义,就是多位数码管的位置选择;通信方式是并行通信,并行通信就是8位一次性传输。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-itUikTcs-1655610173187)(C:/Users/ali126174/AppData/Roaming/Typora/typora-user-images/image-20220617173704194.png)]
而锁存器就是通过一个“开关”,将我们需要的数据传输给数码管,让数码管选择好他应该点亮的位置;这个“开关”就是LE锁存器使能端,在位选中就是P2^7/WELA。
sbit WE = P2^7;
void main()
{WE = 1; //打开U8锁存端P0 = 0xF4; //送入位选信号 0xfe为16进制表示方法,转换 为二进制为1111 0100WE = 0; //关闭U8锁存端
}
注意:WE位选锁存器打开后,一定要锁存就是给WE赋0,因为如果不锁存WE的话,位选锁存器在段选值赋入的时候就被更改了,这也是锁存器最大的功能——锁存。
段选锁存器
当我们找到我们点亮的位置后,我们开始点亮数码管,但是点亮数码管之前,我们应该先清楚数码管的原理和结构;
(左)8段数码管排布图 (右)数码管原理图
我们通过排布图可以看出有七个段和一个点,分别对应的8位2进制(2进制很重要!!),所以我只需要从A到G,dp,从低到高的点灯就可以了。点灯,我们就需要判断怎样让电路导通,
由此我们从原理图中可以看到有两种数码管,分别是共阴极数码管和共阳极数码管。共阴极就是把八条二极管线路的阴极共同接地,共阳极就是把八条二极管线路的阳极共同接VCC,所以共阴极拉高(赋1)导通,共阳极拉低(赋0)导通,STC89C52开发板是共阴极的,所以
下面为共阴极数码码表:
16进制表示 | 显示的数字 |
---|---|
0x3F | 0 |
0x06 | 1 |
0x5b | 2 |
0x4f | 3 |
0x66 | 4 |
0x6d | 5 |
0x7d | 6 |
0x07 | 7 |
0x7f | 8 |
0x6f | 9 |
16进制表示 | 显示的数字 |
---|---|
0x77 | A |
0x7c | b |
0x39 | C |
0x5e | d |
0x79 | E |
ox71 | F |
ox76 | H |
ox38 | L |
ox40 | - |
ox00 | 熄灭 |
STC89C52开发板上所用的是2个四位的数码管,在其内部公共端是独立的,独立的公共端可以用来控制哪一位数码管点亮,段线是连接在一起的,用来负责显示什么数字,我们常常把公共端叫做"位选线",连接在一起的线叫做"段选线"。
sbit WE = P2^7;//定义位选
sbit DU = P2^6;//定义段选
void main()
{WE = 1; //打开位选锁存端P0 = 0x80; //送入位选信号 0xfe为16进制表示方法,转换二进制为1000 0000WE = 0; //关闭位选锁存端DU = 1;//打开段选锁存器P0 = 0x06;//送入段选信号0x06, 0000 0110 显示一个“1” DU = 0;//关闭段选锁存器
}
就此我们就点亮了第一个位置的第一个数码管,点亮为“1”。
后续我们可以拓展一些我们想要的变式:
- 数码管动态显示
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管位选uchar temp;//共阴极数码管段选表0~9
uchar code table[] = {0X3F ,0X06 , 0X5B , 0X4F , 0X66 , 0X6D , 0X7D , 0X07 , 0X7F , 0X6F };void delay(uint z)//定义毫秒级的延时函数
{uint x,y;for(x = z ; z > 0 ; z-- )for( y = 114 ; y > 0 ; y--);
}void display(uint i)//定义一个千位的数码显示函数
{uint thr ,hur ,ser ,num;thr = i / 1000;hur = i % 1000 /100;ser = i % 1000 % 100 / 10;num = i % 10;//第一位数码管P0 = 0xFF;//清除段码WE = 1;//打开位选锁存器P0 = 0xFE;//1111 1110WE = 0; //锁存位选数据DU = 1;//打开段选锁存器P0 =table[thr];DU = 0;//锁存段选数据delay(5);//第二位数码管P0 = 0xFF;//清除段码WE = 1;//打开位选锁存器P0 = 0xFD;//1111 1101WE = 0; //锁存位选数据DU = 1;//打开段选锁存器P0 =table[hur];DU = 0;//锁存段选数据delay(5);//第三位数码管P0 = 0xFF;//清除段码WE = 1;//打开位选锁存器P0 = 0xFB;//1111 1011WE = 0; //锁存位选数据DU = 1;//打开段选锁存器P0 =table[ser];DU = 0;//锁存段选数据delay(5);//第四位数码管P0 = 0xFF;//清除段码WE = 1;//打开位选锁存器P0 = 0xF7;//1111 0111WE = 0; //锁存位选数据DU = 1;//打开段选锁存器P0 =table[num];//0101 1011DU = 0;//锁存段选数据delay(5);
}void main()
{while(1){display(1261);}
}
点亮这个数码管后,有没有发现这些“点灯”,都是直接点灯,没有间接,也不交互,所以我们不让他与我们交互一下,这就有了——独立按键/矩阵按键
按键交互
独立按键/矩阵按是一种0/1式的"scanner",按键其实也是一个“开关”,但不是直接将电源拉低,让电路停止的“电源开关”,他像一个“阀门”,控制“0”/“1”(电路的拉高和拉低),但是注意
按键产生的不是理想的所以存在**“按键抖动”,关于抖动,我们可以通过延时函数delay**解决,让上一个动作再延长一点,再执行下一个动作。
自此我们就可以通过if判断在按键闭合为高时,其他的外设功能应该输出一个什么情况;按键松开为低时,其他的外设功能应该输出一个什么情况。
独立按键
要弄清楚独立按键按下去的时候,按键被拉低的,因为独立按键有一端共同接地所以,当key_s2(key_s3)为0时(按下拉低时),电路导通,功能实现。
#include<intris.h>
#define uchar unsigned char
#define uint unsigned int sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管位选
sbit key_s2 = P3^0;//定义独立按键S2
sbit key_s3 = P3^1;//定义独立按键S3
sbit beep = P2^3; //定义蜂鸣器uchar led;
uchar temp;
uchar sum;//共阴极数码管段选表0~9
uchar code table[] = {0X3F ,0X06 , 0X5B , 0X4F , 0X66 , 0X6D , 0X7D , 0X07 , 0X7F , 0X6F };void delay(uint z)//定义毫秒级的延时函数
{uint x,y;for(x = z ; z > 0 ; z-- )for( y = 114 ; y > 0 ; y--);
}
void main()
{ sum = 0;WE = 1;//打开位选锁存器P0 = 0XFE;//1111 1110WE =0;//锁存位选数据led = 0xFE;P1 = led;delay(150);while(1)
{ led = _crol_(led ,1);//循环左移函数P1 = led ;delay(150);if(key_s2 == 0){delay(40);//按键抖动if(key_s2 == 0){if(sum != 9)sum++;DU = 1;//打开段选锁存器P0 = table[sum];DU = 0;//锁存段选数据 while(!key_s2);//松手检测}beep = 0;//外加蜂鸣器delay(100);beep = 1;}if(key_s3 == 0 ){delay(40);//按键抖动if(key_s3 == 0){if(sum > 0)sum--; DU = 1;//打开段选锁存器P0 = table[sum];DU = 0;//锁存段选数据 while(!key_s3);//松手检测}beep = 0;delay(100);beep = 1;}DU = 1;//打开段选锁存器P0 = table[sum];DU = 0;//锁存段选数据 }
矩阵按键
矩阵键盘一共有4行和4列,共16个键;我们可以采用列扫描和行扫描。列扫描时先把接在列上面的所有IO口拉高,接在行上的所有IO置低。当其中有一列内任何一个按键按下那么整条列线都会被拉低。
当我们采用列扫描时,我们先将P34P37拉高,P30P33拉低,即是P3 = 0xf0(1111 0000);如果这时候有按键按下,那么P3^4~ P3^7 就有一个会变成低电平。因此P3的值就不等于0xf0,按下按键所在的列就会变成低电平,这是就可以判断有按键按下。
然后我们进行行扫描,将P34P37拉低,P3033拉高,P3 = 0x0f,按下按键,P30~P33其中一行就会被拉低;最后我们将行扫描和列扫描的值相加就得出我们需要得某行某列的数值。
S1 | S2 | S3 | S4 |
---|---|---|---|
0xEE | 0xDE | 0xBE | 0x7E |
S5 | S6 | S7 | S8 |
0XED | 0xDD | 0xBD | 0x7D |
S9 | S10 | S11 | S12 |
0XEB | 0xDB | 0xBB | 0x7B |
S13 | S14 | S15 | S16 |
0XE7 | 0xD7 | 0xB7 | 0x77 |
注意别忘记防抖动
void scan()
{//4x4矩阵按键扫描//列扫描P3 = 0xF0;if(P3 != 0xF0){delay(10);//防抖动if(P3 != 0xF0){switch(P3){case 0xE0: num = 0; break;case 0xD0: num = 1; break;case 0xB0: num = 2; break;case 0x70: num = 3; break;}}P3 = 0X0F;//行扫描if(P3 != 0x0F){switch(P3){case 0x0E: num = num + 0;break;case 0x0D: num = num + 4;break;case 0x0B: num = num + 8;break;case 0x07: num = num + 12;break;}}while(P3 !=0x0F);//松手检测beep = 0;delay(100);beep = 1;}
}
总结一下,矩阵按键,当按下那个按键时,他两端的为高电平的端被拉低,故**“两端为低”**,例如S15键,将他按下后,两端拉低,P35和P32为0;
故P3 = 0xDB(1101 1011)就是S15的数值。
同理于独立按键,我们将P3口全部拉高,独立按键的值就是这几个来;
S2 | 0xFE |
---|---|
S3 | 0xFD |
S4 | 0xFB |
S5 | 0xF7 |
最后我们将他们在数码管上显示出来
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char//共阴极数码管段选表:
uchar code table[] = {//0 1 2 3 4 5 6 7 8 9 A
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,
//B C D E F H L N u - 熄灭
0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x54,0x3E,0x40,0x00};sbit WE = P2^7;//位
sbit DU = P2^6;//段
sbit beep = P2^3;//蜂鸣器uchar num = 20;//定义一个按键值void delay(uint z)//定义毫秒级的延时函数
{uint x,y;for(x = z ; z > 0 ; z-- )for( y = 114 ; y > 0 ; y--);
}void scan()
{//4x4矩阵按键扫描//列扫描P3 = 0xF0;if(P3 != 0xF0){delay(10);//防抖动if(P3 != 0xF0){switch(P3){case 0xE0: num = 0; break;case 0xD0: num = 1; break;case 0xB0: num = 2; break;case 0x70: num = 3; break;}}P3 = 0X0F;//行扫描if(P3 != 0x0F){switch(P3){case 0x0E: num = num + 0;break;case 0x0D: num = num + 4;break;case 0x0B: num = num + 8;break;case 0x07: num = num + 12;break;}}while(P3 !=0x0F);//松手检测beep = 0;delay(100);beep = 1;}//独立按键扫描P3 = 0XFF;if(P3 != 0xFF){switch(P3){case 0xFE: num =16; break;//S2case 0xFD: num = 17; break;//S3case 0xFB: num = 18; break;//S4case 0xF7: num = 19; break;//S5}beep = 0;delay(100);beep = 1;}while(P3 != 0xFF);//松手检测}void main(){P0 = 0xFF;//清除WE = 1 ;//打开位锁存器P0 = 0xFE;//0111 1111WE = 0; //锁存while(1){scan();//4*4阵按键扫描DU = 1;//打开段锁存器P0 = table[num];DU = 0;//锁存delay(5); }
}
总结
从上面看,我们有直接点灯和间接点灯
通过这些我们就明白了点灯就是高低电平转换,如何通过高低电平的转换时电路导通让我们的外设功能正常的效果。
学习单片机开发——浅尝点灯的快乐相关推荐
- 51单片机 | 如何学习单片机 | 开发板功能介绍 | 开发板使用方法 | 51单片机介绍
文章目录 一.如何学习单片机 1.学习哪种类型的单片机 2.学习单片机的最佳方法 3.学习单片机的准备工作 4.学习单片机的常见疑问 二.开发板功能及使用介绍 1.开发板功能介绍 2.开发板使用方法 ...
- [转帖]ABAQUS学习和开发浅谈 [原创]
原文地址:http://blog.163.com/paulzxy@126/blog/static/14366276020116861613243/ ABAQUS是非线性有限元分析(Nonlinear ...
- 学习单片机,除了需要电脑以外,还需要以下的一些器材
单片机开发不可避免会遇到很多头疼的问题,例如如何分配CPU的时间.其实到了这个阶段我们要越来越灵活的用单片机,如果什么东西都要自己做,你会累死的.你想一想你要开车,不用什么都自己弄吧,买一辆现成的就可 ...
- c语言使单片机输出低电平,单片机开发中的一些实用技巧
很多朋友正在学习单片机开发技术,但开发中免不了要碰到这样.那样的问题,有些问题可能无碍大局,但有一些问题却直接影响到产品的成本.体积.性能.这里介绍笔者的几个技巧,希望对大家的工作有帮助. 一.C语言 ...
- 浅谈三个星期零基础入门学习Thinkphp5开发restful-api接口的心得和总结
一丢丢心得体会: 首先不得不说一下,学习一门知识,真的就像建一栋高楼一样,地基必须的稳固,否则你辛辛苦苦建的楼可能随时会垮掉,这一点在我学习thinkphp5的路上深有体会,同时了自此我也爱上了写博客 ...
- 论文浅尝 | 当知识图谱遇上零样本学习——零样本学习综述
随着监督学习在机器学习领域取得的巨大发展,如何减少人工在样本方面的处理工作,以及如何使模型快速适应层出不穷的新样本,成为亟待解决的问题.零样本学习(Zero-Shot Learning, ZSL)的提 ...
- 小猪的Python学习之旅 —— 15.浅尝Python数据分析
小猪的Python学习之旅 -- 15.浅尝Python数据分析:分析2018政府工作报告中的高频词 标签:Python 一句话概括本文: 爬取2018政府工作报告,通过jieba库进行分词后做词频统 ...
- 新手学习单片机最常见的六大误区,你进坑了吗?
一.去背寄存器 千万不要去记寄存器,我做开发这么多年了,一个寄存器都记不住. 寄存器一般是我们要使用单片机外设的时候会去配置. 一流的方法是直接参考别人的配置程序. 二流的方法是看数据手册,最傻雕的做 ...
- 如何系统的学习单片机?
我来终极下这个问题. 本人2011年自学单片机成功跨行,那个时候做的第一个项目是平衡小车,现在看起来依然回忆满满. 那年我和很多应届生一样,面临着毕业危机,不知道出来该干什么,家里又没矿,一切只能靠自 ...
- STM32:从菜鸟到牛人就是如此简单!为了学习单片机而去学习单片机的思路是不对的
来源于知乎,版权归原作者所有 为了学习单片机而去学习单片机的思路是不对的 你问: 如何系统地入门学习stm32? 本身就是一个错误的问题 假如你会使用8051 会写C语言 那么STM32本身并不需要刻 ...
最新文章
- Sublime Text 3常用快捷键
- linux运行windows环境变量,使用环境变量识别Cygwin,Linux,Windows
- The Internals of PostgreSQL
- 【经验】刚读硕士怎么感觉学机器学习和深度学习越学越不懂?
- 简单的遮罩层加登录窗效果
- html以图像中心定位,在HTML图像上水平和垂直居中文本(绝对定位)
- 不学Python的同学,“跳一跳”都输了
- c语言程序设计 cap 翁恺,GPS数据处理 翁恺老师C语言程序设计CAP第10章编程题
- Bailian4047 全排列【全排列】
- WinForm timer 控件
- 16进制发送 mqtt客户端调试工具_MQTT Simulate Device(MQTT客户端调试工具)下载 v1.0.7免费版-下载啦...
- [音乐] 逆转裁判1~6【五分半无缝衔接】追求组曲
- EC2 Auto Scaling知识点
- uniapp 获取网络状态_uni-app 获取网络状态
- 【英语】 英语的重音怎么读
- 终端I/O termios属性设置 tcsetattr设置
- 苹果全球开发者大会推出智能音箱网友吐槽Siri“掉链子”
- KSM(Kernel Samepage Merging) 剖析:Linux 内核中的内存去耦合
- 设计一个事务增强的动态代理类, 对持久层的用户的CRUD操作进行事务增强 即:
- c语言bzero函数头文件,嵌入q式c语言-文件操用.doc
热门文章
- 管家婆显示服务器端没有软件狗,管家婆找不到加密狗怎么办.doc
- 一位BAT大牛推荐的程序员必装10款神器软件
- H5游戏开发-搭建开发环境
- PDF转换工具安装教程
- LNK2005符号重定义问题
- Python贴吧小爬虫
- Proface触摸屏与三菱PLC软件仿真(或连接实体PLC)
- 解决VMware虚拟机桥接模式无法上网的解决方法 ubuntu
- 用continue计算100以内奇数和_Python入门19break和continue
- qgridlayout 滚动时固定第一行_【德国进口轴承】滚动轴承组合设计应考虑的问题...