嵌入式学习记录- 2-1~5-2

2-1 点亮一个LED

2023 04 21

单片机是如何控制LED亮灭的?

​ LED的一段连着固定电压的线路,另一端连着MCU的引脚,MCU只需要控制输出这根引脚的电压就可以控制灯的亮灭了

​ MCU中,CPU修改寄存器的值,驱动器读取寄存器的值提供高低电平

#include <REGX52.H>

int main(){
	P2 = 0xEE;//1111 1110
	return 0;
}

2-2 LED闪烁

2023 04 21

在STC-ISP中选择软件延时器生成一个1ms的延迟方法之后改成延迟任意时间的方法
记得#include <INTRINS.H>

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
			_nop_();
			i = 2;
			j = 199;
			do
			{
				while (--j);
			} while (--i);
    }
}

void Delay500ms(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j, k;

    _nop_();
    i = 4;
    j = 129;
    k = 119;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}


int main(){
    while(1){
        Delay(500);
        P2 = 0xFE;//1111 1110
        Delay(500);
        P2 = 0xFF;//1111 1110
    }
    return 0;
}

2-3 LED流水灯

2023 04 21

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}

int main(){
    unsigned int index = 0;// 闪烁灯的位置
    while(1){
        Delay(500);
        P2 = ~(1 << index);
        index++;
        index %= 8;
    }
    return 0;
}

3-1 按键控制LED灯亮灭

2023 04 21

按键接驳的线路是低电平,所以在按下后会使连接的io口变成低电平,不按时是高电平(单片机常高电平)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1VmsNxWn-1682103045711)(51单片机.assets/image-20230421132036013.png)]

include <REGX52.H>#include <REG52.H>多了单位定义(P3_1)

#include <REGX52.H>

int main(){
    while(1){
        if(P3_1 == 1)
            P2 = 0xFF;
        else
            P2 = 0xFE;
    }
    return 0;
}

3-2 消除按键抖动的影响

2023 04 21

#include <REGX52.H>
#include <INTRINS.H>

int main(){
    int static1 = 0;
    while(1){
        if(P3_1 == 0){
            // 没有消抖
            if(P3_1 == 1){
                static1 ^= 1;
            }
        }
        if(static1 == 0)
            P2 = 0xFF;
        else
            P2 = 0xFE;
    }
    return 0;
}

在按下按键时多数时候不起作用,因为对于一个机械开关,在连接和断开时的电流并不是瞬间就变为另一种,而是在抖动中接近.

解决办法有两种,硬件消抖和软件消抖

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}

int main(){
    while(1){
        if(P3_1 == 0){
            Delay(20);// 通过等待20ms消除抖动
            if(P3_1 == 1){
                // 写逻辑写惯了没注意到P2_0的数据也是可以直接读取的
                P2_0 = ~P2_0;
            }
        }
    }
    return 0;
}

3-3 独立按键控制LED显示二进制

2023 04 21

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}

int main(){
    while(1){
        if(P3_1 == 0){
            Delay(20);// 通过等待20ms消除抖动
            if(P3_1 == 1){
                P2--;
            }
        }
    }
    return 0;
}

3-4 独立按键控制LED移位

2023 04 21

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}

int main(){
    int index = 0;
    P2 = 0xFE;
    while(1){
        if(P3_0 == 0){
            Delay(20);// 通过等待20ms消除抖动
            if(P3_0 == 1){
                index++;
                index%=8;
                P2 = ~(1 << index);
            }
        }

        if(P3_1 == 0){
            Delay(20);// 通过等待20ms消除抖动
            if(P3_1 == 1){
                index--;
                if(index < 0) index = 7;
                P2 = ~(1 << index);
            }
        }
    }
    return 0;
}

4-1 静态数码管显示

2023 04 21

数码管

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1YMXLhyq-1682103045712)(51单片机.assets/image-20230421161235244.png)]

数码管有单个数码管和四位一体数码管,也分为共阴极和共阳极.

51单片机的高电平驱动能力较弱,所以如果时共阴极的数码管,单片机控制高电平为亮时需要在中间续上中继器以提高驱动能力.之前LED不用是因为单片机提供的是低电平.

四位一体数码管的控制显示的数字是四个数码管公用的一个,但共阴极部分是分别单独控制的,只需要让同一时刻只有一个数码管是显示,利用人眼视觉暂留达到同时显示的效果.

74HC245在这里起到的是中继器的作用,但其实它还是缓冲器,给LE输出不同的电平,高电平将数据从左到右,低电平将数据送右到左.在这里LE直接接的高电平.

138译码器

四位一体数码管的引脚设计思路已经大大减少了所需的引脚数目,但138译码器可以将需要的引脚数目进一步降低.

8个数码管的亮灭需要单独8个引脚,但我们所用到的状态只有8种,就是各个数码管单独显示的8个状态,8种状态的信息是可以用3个io口传递的

代码

P2_2,P2_3,P2_4三位控制单个数码管的亮灭

P0_0-P0_7控制数码管内8个LED的亮灭

#include <REGX52.H>

void nixie(unsigned char Location,Number){
    switch(Location){
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }

    P0 = 0x7D;
}

int main(){
    nixie(7, 2);
    return 0;
}

效果为倒数第二位显示6

启用Number,用数组存数码管的显示

#include <REGX52.H>

unsigned char nixieTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void nixie(unsigned char location,number){
    switch(location){
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }

    P0 = nixieTable[number];
}

void main() {
    while (1) {
        nixie(2, 0);
    }
}

4-2 动态数码管显示

2023 04 21

#include <REGX52.H>
#include <INTRINS.H>

void delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}
unsigned char nixieTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void nixie(unsigned char location,number){
    switch(location){
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }

    P0 = nixieTable[number];
}

void main() {
    while (1) {
        unsigned char i = 0;
        for(i = 1; i <= 8;i++){
            nixie(i, i-1);
            delay(2);
        }
    }
}

数码管的消影

如果没有delay(2)效果如下:

在这里插入图片描述

数码管显示的流程是:段选 位选 段选 位选 段选 位选

但因为单片机的运算速度很快,在位选到下一位后段选还没反应过来(硬件跟不上),所以会有上一位的残影

修改方法为每显示一位后等待一段时间后将段选清零,这样在下一次的位选->段选流程就不会有上一次的段选残留

#include <REGX52.H>
#include <INTRINS.H>

void delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}
unsigned char nixieTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void nixie(unsigned char location,number){
    switch(location){
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }

    P0 = nixieTable[number];
    delay(1);
    P0 = 0x00;// 如果没有这个的话还是会看见轻微的残留
}

void main() {
    while (1) {
        unsigned char i = 0;
        for(i = 1; i <= 8;i++){
            nixie(i, i-1);
        }
    }
}

数码管驱动方式

单片机直接扫描:硬件设备简单,但会消耗大量的单片机CPU时间

专用驱动芯片:内部自带显存、扫描线路,单片机只需要告诉他显示什么即可

5-1 模块化编程

2023 04 21

main.c

#include <REGX52.H>
#include "delay.h"
#include "nixie.h"

int main(){
    while(1){
        P2 = 0xFE;
        delay(500);
        P2 = 0xFF;
        delay(500);
        nixie(3,3);
    }
}

delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void delay(unsigned int xms);

#endif

delay.c

#include <INTRINS.H>

void delay(unsigned int xms)		//@11.0592MHz
{
    unsigned char i, j;

    while(xms--){
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }
}

nixie.h

#ifndef __NIXIE_H__
#define __NIXIE_H__

void nixie(unsigned char location,number);

#endif

nixie.c

#include <REGX52.H>
#include "delay.h"

unsigned char nixieTable[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};


void nixie(unsigned char location,number){
    switch(location){
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }

    P0 = nixieTable[number];
    delay(1);
    P0 = 0x00;
}

5-2 LCD1602调试工具

2023 04 21

使用LCD1602液晶屏作为调试窗口,提供类似printf函数的功能

函数作用
LCD_Init();初始化
LCD_ShowChar(1,1,‘A’);显示一个字符
LCD_ShowString(1,3,“Hello”);显示字符串
LCD_ShowNum(1,9,123,3);显示十进制数字
LCD_ShowSignedNum(1,13,-66,2);显示有符号十进制数字
LCD_ShowHexNum(2,1,0xA8,2);显示十六进制数字
LCD_ShowBinNum(2,4,0xAA,8);显示二进制数字

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值