650 likes | 835 Views
单片机原理及应用 Microcontroller Principles and Applications 非电量接口 (声、光、机械等). introduction. MCU is not capable to do everything, special components and circuits are always needed Output: LED, 7Seg-LED, relays, LCD, buzzer Speaker, motor, IrDA, For input: Switch, button, keypad Sensor,.
E N D
单片机原理及应用 Microcontroller Principles and Applications 非电量接口 (声、光、机械等)
introduction • MCU is not capable to do everything, special components and circuits are always needed • Output: • LED, 7Seg-LED, relays, LCD, buzzer • Speaker, motor, IrDA, • For input: • Switch, button, keypad • Sensor,
LED • LED(light emitting diode/发光二极管)将电转化为可见光 • PN节结构,正向导通发光,反向截至熄灭。 • 多种颜色,多种尺寸,多种封装 • 控制流经电流决定其亮度,需要使用限流电阻 • LED具有一定的响应速度
Control LED 试验板的LED电路
实验板的核心板上有8个LED指示灯,经245驱动,连接到PORTB上,低电平点亮。控制其闪动的C程序(test1.c)如下:实验板的核心板上有8个LED指示灯,经245驱动,连接到PORTB上,低电平点亮。控制其闪动的C程序(test1.c)如下: void deley(void) { unsigned int i,j; for(i=0;i<1000;i++) for(j=0;j<500;j++); } void main(void) { /* put your own code here */ PORTB=0X55; DDRB|=0XFF; for(;;) { deley(); PORTB_PB0=~PORTB_PB0; PORTB_PB1=~PORTB_PB1; } 此处可解释并演示程序
7-segment LED 7段数码管 • 把7个细长的LED排成‘日’字型 • 单独控制每个段的亮灭,可以表示出数字 0~9 • 使用多个数码管表示数字 • 应用非常广泛 • 多种颜色,多种尺寸
7段数码管原理与结构 • 由7/8个LED共同组成,使用一个公用端, • 共阳型 • 所有LED的阳极连在一起,成为公用端 • 共阴型 • 所有LED的阴极连在一起,作为公用端
7段数码管编码 a 如何表示数字2? abcdefg7个段 哪些点亮,哪些熄灭 f b g c e d
7段数码管编码 a 如何表示数字2? abcdefg7个段 哪些点亮,哪些熄灭 f b g c e d 待表示的数字和abcdefg的状态 构成了7段数码管的编码
7段数码管编码 a f b g c e d 1 – 表示点亮 0 – 表示熄灭
7段数码管编码 a 能否表示ABCDEF? f b g c e d
7段数码管使用 • 使用单个数码管时公用端接入电源或地,用微控制器的IO控制每一个段LED的亮灭。 • IO端口的值就是数码管编码,由待显示的数据决定 • 多位数码管表示一个多位数时,每个数码管仅能表示一位,对每位都要进行编码转换 • 多个数码管可以使用动态扫描的方法节约IO端口。
数码管动态扫描 • 通过位控制信号使得任意时刻只有一位数码管处于显示状态 • 通过段控制信息确定该位数码管显示的数字 • 定时更改位控制信息和段控制信息 • 利用视觉暂留现象得到稳定的数字显示 • 多个LED同时点亮的电流都经过公共端,MCU的IO无法承受,必须使用三极管 段控制 位控制 此处可在黑板画时序图解释动态显示过程
数码显示实验 • 实验板上有4位数码管,共阳极结构,与前图一样,不过段选和片选控制都经过7407驱动,引出12根连线,对应关系如下 实验中可将段选连接到PORTP,将片选连接到PORTT,连线关系如下:
连好之后,就可以先将一个数码管点亮,C程序(test2.c)如下:连好之后,就可以先将一个数码管点亮,C程序(test2.c)如下: DDRP|=0XFF; DDRT|=0XFF; //点亮一个数码管,显示2 PTP=~0x5b; PTT=0xfe; 此处可解释点亮原理并解释演示程序
对与数码管控制,直接控制段码并不方便,正如在数字电路中有BCD-7段码译码器,在程序中可以使用软件译码的方式,例程(test2.c)如下:对与数码管控制,直接控制段码并不方便,正如在数字电路中有BCD-7段码译码器,在程序中可以使用软件译码的方式,例程(test2.c)如下: //软件BCD-7段译码 const unsigned char DisplayDecode[]={~0x3f,~0x06,~0x5b,~0x4f,~0x66,~0x6d,~0x7d,~0x07,~0x7f,~0x6f,~0x77,~0x7c,~0x39,~0x5e,~0x79,~0x71};//0-9 ABCDEF PTP=DisplayDecode[3]; Why use const?好处? 此处可解释软件译码原理和好处并演示程序
目前,我们已点亮一个数码管,但实际我们需要点亮全部数码管并显示不同内容,按前面的分析,必须采用动态显示的方式,按人眼的反应,刷新频率得大于80Hz,即每段显示3ms。这个3ms可以用软件延迟实现,但为提高CPU效率,一般使用定时器。C程序(test3.C或test4.c)如下:目前,我们已点亮一个数码管,但实际我们需要点亮全部数码管并显示不同内容,按前面的分析,必须采用动态显示的方式,按人眼的反应,刷新频率得大于80Hz,即每段显示3ms。这个3ms可以用软件延迟实现,但为提高CPU效率,一般使用定时器。C程序(test3.C或test4.c)如下: //动态显示,4个数码管显示不同内容 if(DisplayPauseTimer==gPIT_counter) { PTT|=0xf; DisplayPauseTimer+=1;//100 DisplayNumber++; if(DisplayNumber>=4) DisplayNumber=0;
PTP=DisplayDecode[DisplaySuma[DisplayNumber]]; switch(DisplayNumber) { case 0: PTT&=0xfe; break; case 1: PTT&=0xfd; break; case 2: PTT&=0xfb; break; default: PTT&=0xf7; break; } } 此处需回顾PIT的使用,解释多任务调度、好处 并演示程序
Switch - 开关 • 开关有两种状态-闭合和断开 • 船形开关,拨位开关 • 同一个开关可以提供多组触点
开关状态的读取 • 利用外部电路使得开关的闭合和断开状态能得到两种不同的电平值 • 开关断开时要有默认电平值(上拉/下拉) 5V MCU的IO口
按键 • 带有自恢复装置的开关,常开常闭型 • 各种形状,各种尺寸 • 耐高压,轻触式,带指示 • 一个按键也可以提供多组触点
按键 • 用于产生一个脉冲 • 按下和释放的时刻会有抖动 • 需要设计去抖动电路或软件去抖
键盘 • 不同于开关,按键可以自行释放 • 如果多个按键不会同时按下,就可以做成键盘,利用扫描方式获取按键信息,减少占用的IO数目。
键盘 • 键盘由多个按键组合而成
5V 键盘 1个MCU的IO口,可以检查 一个按键的状态 包含16个按键的键盘 需要多少个IO来连接?
5V 行端口 列端口 键盘 可以利用扫描方式获取按键 信息,减少占用的IO数目
0 1 1 1 1 1 1 1 逐行扫描 对第一行进行扫描: 行输出端口输出 0111 检查列回读端口的值 5V 行端口 列端口
5V 1 0 1 1 1 1 0 1 1 1 1 1 逐行扫描 对第一行进行扫描: 行输出端口输出 0111 检查列回读端口的值 对第二行进行扫描: 行输出端口输出 1011 检查列回读端口的值 行端口 最坏的情况下需要进行4次扫描过程,faster? 列端口
0 0 0 0 1 1 1 1 1 0 1 1 反转扫描 5V 行端口输出 0000 检查列端口的值 根据列端口的值,已经可以确定 在哪一列有键按下 行端口 列端口
1 1 0 1 1 1 1 1 0 0 0 0 反转扫描 行端口输出 0000 检查列端口的值 根据列端口的值,确定 哪一列有键按下 将行端口和列端口 输入输出方向反转 列端口输出0000 检查行端口的值 根据行端口的值,确定 哪一行有键按下 5V 行端口 列端口
反转扫描 • Hey,Wait。。。。。。 • 行列反转时上拉电阻怎么办? • OK。。。。 • 给行列都加上上拉电阻 • 缺点 • 作为输出时,这个上拉电阻其实没有什么作用,反而白白消耗了电流 • 改进 • 用MCU端口的内部上拉电阻,根据输入输出状态进行动态配置 • 限制 • 有些IO端口只支持成组打开/关闭上拉电阻。那么需要两个端口的IO配合使用。 • 有些IO端口的每一个引脚都有独立的上拉电阻控制位。 Perfect!
0 1 1 1 1 1 1 1 多键按下的扫描识别 5V 对第一行进行扫描: 仅第一行输出, 其余行端口为输入 检查所有输入端口 5V 行端口 列端口
1 0 1 1 1 1 1 0 1 1 1 1 逐行扫描 5V 对第一行进行扫描: 对第二行进行扫描: 仅第二行输出, 其余行端口为输入 检查所有输入端口 5V 行端口 列端口
1 1 0 1 1 1 1 1 1 1 0 1 逐行扫描 5V 对第一行进行扫描: 对第二行进行扫描: 5V 对第三行进行扫描: 仅第三行输出, 其余行端口为输入 检查所有输入端口 行端口 列端口
1 1 1 0 1 1 1 1 逐行扫描 5V 对第一行进行扫描: 对第二行进行扫描: 5V 对第三行进行扫描: 对第四行进行扫描: 仅第四行输出, 其余行端口为输入 检查所有输入端口 行端口 列端口
扫描策略 • 循环扫描? • 可行,可靠 • 占用CPU时间 • 定时扫描 • 可能丢失按键动作 • 键盘中断! • 发现有任何按键按下时启动扫描
0 0 0 0 1 1 1 1 键盘中断-无键按下 5V 行端口输出 列端口等待键盘中断
0 0 0 0 1 1 1 1 0 1 1 1 键盘中断-有键按下 5V 行端口输出 列端口产生键盘中断
本实验板上有一个4*4的薄膜键盘,板上无上拉电阻,接口是X1-4、Y1-4,实验中可将其连接到PORTA口上,连线关系如下:本实验板上有一个4*4的薄膜键盘,板上无上拉电阻,接口是X1-4、Y1-4,实验中可将其连接到PORTA口上,连线关系如下: 采用逐行扫描的方式,Y1-4(PA0-3)为输出, X1-4(PA4-7)做为输入,使能PORTA的上拉电阻,周期循环扫描,间隔25ms,一次一行,100ms完成一次扫描。在这样取样间隔下,已滤除按键抖动。C程序(test4.c)如下:
DDRA=15;//输出 /*Ports ABEK, BKGD pin Pull-up Control Register (PUCR) 7:PUPKE 6:BKPUE 5:0 4:PUPEE 3:0 2:0 1:PUPBE 0:PUPAE */ PUCR|=(1<<0); //行列键盘检测 if(KeyDetectTimer==gPIT_counter) { KeyDetectTimer+=10; KeyCurentInput=PORTA; KeyCurentInput>>=4; KeyInputStat=((KeyLastInput[KeyLine]^KeyCurentInput)&KeyLastInput[KeyLine]); KeyLastInput[KeyLine]=KeyCurentInput; 此处需解释 并演示程序
if(KeyInputStat&15) { for(i=0;i<4;i++) { if(KeyInputStat&1) { DisplaySuma[3]=DisplaySuma[2]; DisplaySuma[2]=DisplaySuma[1]; DisplaySuma[1]=DisplaySuma[0]; DisplaySuma[0]=KeyV[KeyLine][i]; break; } KeyInputStat>>=1; } } KeyLine++; if(KeyLine>=4) KeyLine=0;
switch(KeyLine) { case 0: PORTA=~1; break; case 1: PORTA=~2; break; case 2: PORTA=~4; break; default: PORTA=~8; break; } } unsigned char KeyCurentInput=0,KeyInputStat,KeyLastInput[4],i; const unsigned char KeyV[4][4]={1,2,3,4,5,6,7,8,9,0,10,11,12,13,14,15};
Buzzer-蜂鸣器 • 将电转换为声的器件 • 电平驱动和脉冲驱动
蜂鸣器驱动电路 • 蜂鸣器需要较大电流,MCU的IO不能提供足够的电流 • 需要使用驱动电路
Relay-继电器 • 继电器用于输出隔离 • 电磁线圈 • 单刀双掷,双刀双掷 • 常开常闭节点 • 耐高压,大电流
Relay-继电器 • 基于电磁作用,控制信号和被控制开关之间没有电气联系,被控制端的电气干扰被有效的隔离。 5V ~ 220V
Opto-coupler 光耦 • 用于输入隔离,避免外部输入的噪声进入单片机系统 • 静电冲击ESD保护 • 多通道,不同封装 • 速率,工作电压
Opto-coupler 光耦 5V 24V