历史上的今天
返回首页

历史上的今天

今天是:2025年02月12日(星期三)

正在发生

2020年02月12日 | AVR单片机学习按键与数码管的程序设计

2020-02-12 来源:eefocus

简介:按键与数码管的程序设计
AVR IO口的输入模式与上拉电阻
选择结构语句与按键的查询方式程序设计
数码管基本原理
扫描方式显示多位数码管



一、输入状态IO寄存器设置


1、DDRx 某一位置0,相应位的IO口被设置为输入


2、PORTx某一位置1,使能对应IO口相应位的上拉电阻


3、PINx的对应位是输入的数据,0或1


选择结构语句


一、关系运算符和关系表达式


小于< 小于等于<= 大于> 大于或等于== 不等于!=


二、逻辑运算符和逻辑表达式


逻辑与&&逻辑或||逻辑非!


三、if 语句结构


if(表达式1)语句1


else if(表达式2)语句2


else 语句3


四、switch 语句结构


switch(表达式)


{case 常量1:表达式1


case 常量2:表达式2


.........


default:表达式n}


按键的查询方式程序设计


一、PIND & (1<<6)


二、1<<6


1、1左移6位,即:0b01000000


怎么判断一个按键按下了呢?首先看下图是4个按键













第一个是PD2 上一段接VCC 其他都是一段接IO(PD3 PD6 PD7)口另一端接地线。


所以当按键闭合时候相应IO都输入一个0,当按键抬起来的时候IO输入多少呢?


所以这些IO口必须将上拉电阻进行使能,将按键打开相当于输入一个1.所以我们判断这3个按键按没按下去的话,就判断输入是不是0就行了。


对于第一个按键如果按下输入是1,当抬起来时候由于AVR内部不带下拉电阻的,所以按键打开时候输入是0.


所以就需要判断某一位是0,还是1.某一位是0还是1就用到了& 与运算了。 1 跟1 与就1 1 与0 就是0


上面代码(temp& (1<<6)) (temp & 0b01000000) temp本身值不变,只是结果来判断某一位是0还是1


比如:PD6 上的K3 因为PD6 所以 PIND &(1<<6)的结果就行了


三、PIND & (1<<6)


1、移除第6位之外其他位清零


2、第6位保持输入的值


四、与选择结构语句的结合


1、判断PIND & (1<<6)的值,执行相应代码



除非你上电之前一直讲按键按下,否则上电的一瞬间程序就执行到while(1);了所以要将他们加入到死循环里面如下图


这样就实现了按键的不停的检测。 其实DDRD 上电默认都是0 所以清0 置为输入也没有意义。


程序在if判断设置断点然后全速执行可以看到只要没有按键按下程序进不去断点,如果我们在板子上按下K3则如下图所示进入断点,再按下单步执行蜂鸣器响了如图。



所以这个程序就达到了我们的目的。


现在换一种判断 就是按键被按下而不是没被按下 用逻辑非


这样达到了预想的目标。但是这样只能判断一个按键如果多个按键怎么办呢?2种办法


一、采用if elseif else


if (){


elseif{


}


elseif {


}


else{




}


}


二、采用


switch (表达式){


case 相符合的条件 {


break;


}


case 相符合的条件{


break;


}


default{




}


}


一、用if 实现


#include

int main(void){

//PD6 设置为输入 K3

DDRD &= ~(1 << 6);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<6);

//PD7 设置为输入 K4

DDRD &= ~(1 << 7);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<7);

//PD2 设置为输入 K1

DDRD &= ~(1 << 2);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<2);//这个上拉不上拉没关系因为上拉是百K的电阻所以开关打开还是认为是低电平

//PD3 设置为输入 K2

DDRD &= ~(1 << 3);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<3);


//蜂鸣器PA3 设置方向寄存器为输出

DDRA |= (1<<3);

//蜂鸣器关掉

PORTA &= ~(1<<3);

//流水灯端口全部设为输出

DDRB = 0xff;

while(1){

//判断PIND 这位是否为1 为真的话就是按键没有按下

if (!(PIND & (1<<6))){ //本来没有按下 进入 现在变成了没有按下 不进入了取非了 被按下进入了 PD6

//按键被按下用蜂鸣器表示一下 PA3

PORTA |= (1<<3);

}

else if(!(PIND & (1<<7))){ //PD7 K4按下让流水灯产生动作 必须上面使能K4上拉电阻

PORTB |= (1<<0);//第一个灯发光 就是等于1

}

else if (PIND & (1<<2)){//因为按下的时候是低电平接的是电源

//第二个灯发光

PORTB |= (1<<1);

}

else if (!(PIND & (1<<3))){

//第三个灯发光

PORTB |= (1<<2);

}

else{

//变成了按键没有按下

PORTA &= ~(1<<3); //蜂鸣器

PORTB = 0;//灯

}

//看到没有按下一直响的,按下就不响了。

}

}


---------------------------------------------------------------


二、用switch 来实现就需要一次性将这四位读回来。 代码如下


#include

int main(void){

//PD6 设置为输入 K3

DDRD &= ~(1 << 6);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<6);

//PD7 设置为输入 K4

DDRD &= ~(1 << 7);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<7);

//PD2 设置为输入 K1

DDRD &= ~(1 << 2);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<2);//这个上拉不上拉没关系因为上拉是百K的电阻所以开关打开还是认为是低电平

//PD3 设置为输入 K2

DDRD &= ~(1 << 3);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<3);

//蜂鸣器PA3 设置方向寄存器为输出

DDRA |= (1<<3);

//蜂鸣器关掉

PORTA &= ~(1<<3);

//流水灯端口全部设为输出

DDRB = 0xff;

while(1){

//首先一次性将这4个位都读回来 2 3 6 7 脚

switch(PIND & 0b11001100) {

case 0b11001100: {//只有第一个按键按下 0b11001100 接的电源按下是1

//LED 0 发光

PORTB |= (1<<0);

break;

}

case 0b11000000: {//只有第 二个按键按下 0b11001100 接的电源抬起是0

//LED 0 发光

PORTB |= (1<<1);

break;

}

case 0b10001100: {//只有第三个按键按下 0b11001100 接的电源抬起是0

//LED 0

PORTB |= (1<<2);

break;

}

case 0b01001100: {//只有第四个按键按下 0b11001100 接的电源抬起是0

//LED 0 发光

PORTB |= (1<<3);

break;

}

default :{ //都没有按下 0b11001000 因为有下拉

//变成了按键没有按下

PORTA &= ~(1<<3); //蜂鸣器

PORTB = 0;//灯


break;

}

}


//判断PIND 这位是否为1 为真的话就是按键没有按下


}

}


-------------------------------------------------------------------------


以上都是查询方式因为都是在while循环一边一边的查询,按键有动作就执行相应的代码这样很耽误CPU的时间的,在下一篇博客我会稍微降讲用中断的方式来编写按键的程序。下面继续说呵呵、


八段数码管


一、八段数码管


1、八段数码管由八段LED构成


2、各LED阴极或阳极并在一起,称为“位选线”:共阴、共阳


3、其余8个引脚各自引出,称为“段选线”,各段可以分别控制






记住一般一位的数码管有10个脚


个人理解:(其中2脚是连在一起的是公共端。其他8个是段选 比如1、6接电源 其他接IO口个人理解的)


多位合一的数码管


一、多位合一的数码管


1、将多个八段数码管的段选线分别并在一起,位选线引出如下图



由上图看出是4位 应该是8个段选线(7段加一个点) 4个位选线 共12根线 。


com0 ---- com3 是位选


a-g 加 dp 是段选。


多位数码管的使用


1、多位数码管的各个位均可以单独显示不同的数据,但一个时刻只能点亮一位、(点快点人眼看不出来)


2、依次点亮多位数码管中的各个位,由于人眼的视觉暂留效应,看起来是同时点亮


3、如下图是电路图 硬件电路是下图设计的






它的每一段相当于一个发光二极管,电流大约是10个mA左右(5--10)mA,因此段选可以直接用单片机的IO驱动是足够的不论是拉电流还是灌电流,这里面我们用的是一个共阴极的数码管,因此应该是向外拉电流,而段选线我们可以计算下段选线上最大电流时多少?假设每段都点亮没段是10mA的话,那么位选线上也就是10*8 = 80mA 所以我们不能用IO口,一般的单片机不可能输出这么大的电流,所以我采用一个三极管来进行驱动,共阴极的数码管一般要用NPN型的数码管,它的接法如下图的样子。




再来张清楚点的下图





可以看到C0 接的是COM0位选线,IO口通过1K电阻接到三极管基极上,如果IO是个高电平的话电流就通过三极管到射极流下来的,因此三极管达到饱和,CO点相当于导通相当于接地。4个段选分别接到PA4到PA7 四个IO口上因此我们写程序首先将PA4 输出一个1 PA5 PA6 PA7 全都输出0 这样我们选中第0个第一位数码管此时在PB口上输出的数据就会显示在数码管上面。编写程序:





设置一个断点然后再单步调试(F10)。看看它显示的是那一段。同时流水灯也亮了,因为是同一个IO口。这样对应PB上的每一段都找到了。


好了这样我们就去编写一下数码管的段码;


首先是显示1 只要将需要点亮的各个段置1就实现了段码的功能,具体的编写过程自己去画画看



这是我自己用数组的形式定义的。


首先是什么类型的数组 名称 元素个数


0-9


A-F


全部显示出来就是16个元素,一个字符型数加一个逗号分开。一直放16个,使用时候要从第0个开始下标从0开始的。


#include

int main(void){

//PD6 设置为输入 K3

DDRD &= ~(1 << 6);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<6);

//PD7 设置为输入 K4

DDRD &= ~(1 << 7);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<7);

//PD2 设置为输入 K1

DDRD &= ~(1 << 2);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<2);//这个上拉不上拉没关系因为上拉是百K的电阻所以开关打开还是认为是低电平

//PD3 设置为输入 K2

DDRD &= ~(1 << 3);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<3);

//蜂鸣器PA3 设置方向寄存器为输出

DDRA |= (1<<3);

//蜂鸣器关掉

PORTA &= ~(1<<3);

//数码管全部置为输出

DDRB = 0xff;

//位选线高四位全部置1 也是输出 因为是置其中4位所以用|=

DDRA |= 0Xf0;

char scandata[16]={

0b10101111,//0

0b10100000,//1

0b11000111,//2

0b11100110,//3

0b11100000,//4

0b01101110,//5

0b01101111,//6

0b10100010,//7

0b11101111,//8

0b11101110,//9

0b11100111,//A

0b01101101,//b

0b00001111,//c

0b11000001,//d

0b01001111,//E

0b01001111//F


};

while(1){

//数码管也需要扫描所以也用死循环 while(1)

//先将数码管的第一位点亮 选中位选

PORTA |=(1<<4);

//再将数据送到PB口上哪一段对应哪一位要事先测量下 编一个程序测量下

PORTB = scandata[0];//显示0

PORTB = scandata[1];//显示1

PORTB = scandata[2];//显示2

PORTB = scandata[3];//显示3

PORTB = scandata[4];//显示4

PORTB = scandata[5];//显示5

PORTB = scandata[6];//显示6

PORTB = scandata[7];//显示7

PORTB = scandata[8];//显示8

PORTB = scandata[9];//显示9

PORTB = scandata[10];//显示A

PORTB = scandata[11];//显示B

PORTB = scandata[12];//显示C

PORTB = scandata[13];//显示D

PORTB = scandata[14];//显示E

PORTB = scandata[15];//显示F


}

}

//这就是数码管用段码显示。那么怎么对数码管扫描显示呢?


我们可以遵循这样一个顺序,首先将数码管位选中,送数据PORTA 选中 PORTB送上数据然后打开相应这一位。让他显示出来,显示出来之后呢?再让这一位熄灭可以把所有四位都熄灭 位选 PORTA &0x0f;高四位清0这样就完成了数码管的高四位显示。


#include

int main(void){

int j ;


//PD6 设置为输入 K3

DDRD &= ~(1 << 6);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<6);

//PD7 设置为输入 K4

DDRD &= ~(1 << 7);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<7);

//PD2 设置为输入 K1

DDRD &= ~(1 << 2);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<2);//这个上拉不上拉没关系因为上拉是百K的电阻所以开关打开还是认为是低电平

//PD3 设置为输入 K2

DDRD &= ~(1 << 3);

//输入状态下将数据寄存器使能上拉电阻

PORTD |= (1<<3);

//蜂鸣器PA3 设置方向寄存器为输出

DDRA |= (1<<3);

//蜂鸣器关掉

PORTA &= ~(1<<3);

//数码管全部置为输出

DDRB = 0xff;

//位选线高四位全部置1 也是输出 因为是置其中4位所以用|=

DDRA |= 0Xf0;

char scandata[16]={

0b10101111,//0

0b10100000,//1

0b11000111,//2

0b11100110,//3

0b11100000,//4

0b01101110,//5

0b01101111,//6

0b10100010,//7

0b11101111,//8

0b11101110,//9

0b11100111,//A

0b01101101,//b

0b00001111,//c

0b11000001,//d

0b01001111,//E

0b01001111//F


};

while(1){

//数码管也需要扫描所以也用死循环 while(1)

//先将数码管的第一位点亮 选中位选

PORTA |=(1<<4);

//再将数据送到PB口上哪一段对应哪一位要事先测量下 编一个程序测量下

PORTB = scandata[0];//显示0

for (j=0;j<400;j++);//延时

PORTA &= 0x0f;

PORTA |= (1<<5);

PORTB = scandata[1];

PORTA &= 0x0f;

for (j=0;j<400;j++);//延时

PORTA |= (1<<6);

PORTB = scandata[2];

PORTA &= 0x0f;

for (j=0;j<400;j++);//延时

PORTA |= (1<<7);

PORTB = scandata[3];

for (j=0;j<400;j++);//延时

PORTA &= 0x0f;

//单步仿真看看 就是1位亮了0 熄灭 2位亮1 熄灭 3位亮2 熄灭 4位亮3 熄灭 一直循环

//全速执行看看显示4个数字可以看到亮度不怎么亮的,因为 点亮熄灭只有那么一小段时间是发光的

//所以如果要增加亮度只需要加一个延时程序 声明一个变量j 在看效果 全速执行亮度是明显增加了

//这就是数码管程序扫描的程序设计


}

}

推荐阅读

史海拾趣

广州盛炬(GZSJ)公司的发展小趣事

机顶盒,全称为数字视频变换盒(Set Top Box,简称STB),是现代家庭娱乐系统中不可或缺的关键设备。它作为连接电视机与外部信号源的桥梁,能够将接收到的数字电视信号转换成适合电视播放的格式,极大地丰富了用户的视听体验。

机顶盒的起源可追溯至20世纪90年代初,最初是为了解决有线电视收视费问题而设计的解扰设备。随着数字电视技术的发展,机顶盒的功能不断扩展,现已成为集数字信号接收、解码、显示以及多种增值服务于一体的智能终端。

从技术层面看,机顶盒支持多种信号源,包括有线电缆、卫星天线、宽带网络及地面广播等。它不仅能够接收高清、超高清电视节目,还能提供电子节目指南(EPG)、因特网网页浏览、视频点播、游戏等多元化服务。此外,一些先进的机顶盒还集成了智能语音助手、云计算和边缘计算技术,实现了更为便捷、智能的用户交互和内容分发。

在内容创新方面,机顶盒通过与各大内容提供商合作,不断引入优质资源,如电影、电视剧、综艺节目等,并根据用户偏好提供个性化推荐服务。同时,其跨平台整合能力也使得用户可以在不同设备间无缝切换,享受高质量的视频内容。

综上所述,机顶盒作为数字电视技术的核心组成部分,以其强大的功能、丰富的内容和便捷的操作体验,成为了现代家庭娱乐的重要选择。随着技术的不断进步和市场的持续扩大,机顶盒将继续发展,为用户带来更加优质、便捷、智能的观影体验。

AZM [Arizona Microtek, Inc]公司的发展小趣事

随着市场规模的扩大,AZM公司面临着供应链管理和成本控制的挑战。为了确保产品质量和交货期的稳定性,公司加强了与供应商的合作与沟通,建立了严格的供应商评价体系。同时,公司还通过优化生产流程、提高生产效率、降低原材料消耗等方式,有效控制了成本,提升了盈利能力。

倍思特(BEST)公司的发展小趣事

为了进一步提升公司的国际竞争力,AZM公司开始实施国际化战略。公司积极寻求与国际知名企业的合作机会,通过技术合作、市场合作等方式,共同开拓全球市场。同时,AZM公司还在海外设立了研发中心和生产基地,以便更好地了解当地市场需求和技术发展趋势,实现全球布局和资源整合。

请注意,这些故事是基于假设和推测构建的,并非AZM公司的真实发展历程。如果需要了解AZM公司的具体发展历程和故事,建议查阅该公司的官方网站、新闻报道或相关文献资料。

Force Technologies Ltd公司的发展小趣事

背景:随着全球对环境保护意识的增强,Force Technologies Ltd积极响应号召,将绿色环保理念融入企业发展中。

发展:公司投入巨资研发环保型电子产品和制造工艺,致力于减少生产过程中的废弃物排放和能源消耗。同时,公司还积极推动供应链的绿色化转型,与供应商共同制定环保标准和措施。这些努力不仅提升了公司的社会形象,还为其赢得了更多消费者的信赖和支持。

Geo Semiconductor Inc公司的发展小趣事
针对CPU等发热量大的元件,增加散热片、风扇等散热措施,确保元件在正常工作温度范围内运行。
BusBoard公司的发展小趣事

一个优秀的企业不仅要有优质的产品和服务,还要有独特的企业文化。BusBoard公司注重企业文化的建设和传承,通过举办各种活动、培训等方式,让员工更好地了解公司的价值观和发展理念。同时,公司还鼓励员工积极参与公司事务、提出建设性意见,让员工成为公司发展的重要力量。这种以人为本的企业文化使得BusBoard公司的员工队伍更加团结、稳定和有活力。

以上五个故事从不同角度展示了BusBoard公司发展起来的相关情况。这些故事不仅反映了公司的成长历程和发展成果,也体现了公司在电子行业中的地位和影响力。随着科技的不断进步和市场需求的不断变化,BusBoard公司将继续保持创新、拓展市场、提升品质、建设文化,为电子行业的发展贡献更多的力量。

问答坊 | AI 解惑

电子万年历我成功调试过

http://blog.163.com/li_j920/edit/ 还的硬件电路,你们要我会给你们的。…

查看全部问答>

求助IIC总线

在网上看了IIC总线的资料但是还是不懂如何用C语言写个程序出来,看了人家的程序也不懂,请哪些高手帮助我下解释程序的含义,或者进一步讲解下思路。 我看了下资料,不知道这样可以实现IIC总线的启停吗? #include <reg51.h>#include \"intrin ...…

查看全部问答>

WinCE中如何调用ARM汇编指令?

RT,我在做GBA模拟器,想直接调用ARM汇编指令,利用ARM9模拟ARM7-TDMI,但是如果可以直接调用ARM汇编指令模拟就很简单了,请问需要什么平台和设备?因为主要是在Windows Mobile上面用,所以希望能简单一点的…

查看全部问答>

请教 关于上层过滤器驱动程序的问题

请问如何在上层过滤驱动实现指定的IRP拦截,比如,禁止C:\\helloworld.exe以外的一切程序写G:\\盘? 我现在用DriverStudio生成了一个upper filter,那么应该如何修改代码呢?…

查看全部问答>

想找个师傅带一下【上海,武汉均可】

要毕业了没有工作经验,想找一个师傅教一下。毕业课题是无线点菜机,辅导我做一下。…

查看全部问答>

ARM的IO脚为什么不像51那样可以直接操作

arm是先要打开指定的IO口才可以读写,感觉不如51的方便arm的IO脚为什么不像51那样可以直接操作?这样有什么好处?…

查看全部问答>

GBT 20234-2006电动汽车传导充电用插头、插座、车辆耦合器和车辆插孔通用要求

GBT 20234-2006电动汽车传导充电用插头、插座、车辆耦合器和车辆插孔通用要求…

查看全部问答>

zigbeePro实际最多能接多少个节点?

zigbeePro实际最多能接多少个节点?想将一个网络的节点数布置为1000个,分5个楼层,不知延时会有多少?…

查看全部问答>