当前位置: 首页 > news >正文

点灯、点各式各样的灯

鱼离水则身枯,心离书则神索。

    • 前言
    • 闪灯
    • 呼吸灯
    • 流水灯
    • 二进制数显示灯
    • 蜂鸣器节拍
    • 流水音乐会
    • 总结


前言

上回书咱们简单了解了一点有关特殊功能寄存器sfr、通用输入输出GPIO、位操作运算符sbit和一个不靠单片机上的晶振(拿来定时的)的依托于单片机CPU空操作的ms级延时函数,这节课咱们来复盘一下并更深入的实操一下

闪灯

既然咱们已经能让LED亮起来了,那一闪一闪亮晶晶对咱们来说也就只是加一个延时函数的事情:

#include<regx52.h>

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    while(1) {
        P2_0 = 0;       // 点亮LED
        delay_ms(100);
        P2_0 = 1;       // 熄灭LED
        delay_ms(100);
    }
}

呼吸灯

咱们可是会利用变量的,那当然可以让它闪烁的频率像一个垂垂老矣的迟暮耄耋老者愈发慢下来

#include<regx52.h>

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    unsigned int i = 100;
    while(1) {
        P2_0 = 0;       // LED亮
        delay_ms(i);
        P2_0 = 1;       // LED灭
        delay_ms(i);
        if(++i >= 1000) i = 100; // 呼吸范围控制
    }
}

流水灯

一个LED太孤单了,让咱们把一个GPIO口的八个LED伙伴都运行起来呢?

#include<regx52.h>

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    unsigned int i;
    while(1) {
        for(i=0; i<8; ++i) {
            P2 = ~(1 << i); // 流水灯位移
            delay_ms(100);
        }
    }
}

咱知道,这里肯定会有朋友直接懵逼了,因为咱们之前点亮LED使用的是位操作法,即使用sbit对寄存器地址的某一单独位定义后进行操作;但是咱们这么想,这里一个地址对应八个二进制数也就是八个LED,要定义代码冗余且不说效率也低啊,万一以后老板让我同时控制音乐会上的几万个LED光代码就几万行也太难写了,于是咱们引入总线操作法,也就是一次性操作整个P2端口(8个引脚)的方法:咱上一篇说到过一个GPIO对应的特殊功能寄存器sfr绑定的地址有八个二进制数,诶,那咱们直接写入一个表示八位二进制数转换成十六进制的数不就好了吗
但是这里的核心代码 P2 = ~(1 << i); // 流水灯位移还是看不懂咋办?别急,这里涉及到位运算取反操作的一些性质,咱这样列个表会清晰很多:

i值1 << i(二进制)取反操作(~)最终P2输出(十六进制)点亮效果
000000001111111100xFE第1个LED亮
100000010111111010xFD第2个LED亮
200000100111110110xFB第3个LED亮
300001000111101110xF7第4个LED亮
400010000111011110xEF第5个LED亮
500100000110111110xDF第6个LED亮
601000000101111110xBF第7个LED亮
710000000011111110x7F第8个LED亮

等效的位操作法代码:

#include<regx52.h>

// 定义所有LED引脚
sbit LED0 = P2^0;
sbit LED1 = P2^1;
sbit LED2 = P2^2;
sbit LED3 = P2^3;
sbit LED4 = P2^4;
sbit LED5 = P2^5;
sbit LED6 = P2^6;
sbit LED7 = P2^7;

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    unsigned char i;
    while(1) {
        // 正向流水灯
        for(i=0; i<8; ++i) {
            // 关闭所有LED
            LED0 = 1;  // 高电平熄灭
            LED1 = 1;
            LED2 = 1;
            LED3 = 1;
            LED4 = 1;
            LED5 = 1;
            LED6 = 1;
            LED7 = 1;
            
            // 点亮当前LED
            switch(i) {
                case 0: LED0 = 0; break;  // 低电平点亮
                case 1: LED1 = 0; break; 
                case 2: LED2 = 0; break; 
                case 3: LED3 = 0; break; 
                case 4: LED4 = 0; break; 
                case 5: LED5 = 0; break; 
                case 6: LED6 = 0; break; 
                case 7: LED7 = 0; break; 
            }
            delay_ms(100);
        }
    }
}

二进制数显示灯

诶,恭喜你,已经把成都理工大学单片机课程中的GPIO实验做得七七八八了,接下来你会问:“主播主播你的设计确实简单,但是还是太无聊了,有没有什么既简单又有意思的实验?”,有的兄弟,有的,来看看这一款八位二进制数显示灯,先看代码:

#include<regx52.h>

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    unsigned char counter = 0;
    while(1) {
        P2 = ~counter;  // 二进制显示
        delay_ms(100);
        counter++;
    }
}

counter从0(0000,0000)到255(1111,1111)循环,可以直观感受二进制进位(看到LED的波浪式闪烁)


蜂鸣器节拍

蜂鸣器一般分为有源蜂鸣器和无源蜂鸣器,按咱现在的学习和知识储备直白地来说,前者音调较为固定(可用PWM调制,后面会讲,但是效果不好),无源蜂鸣器则音域较广(PWM调制效果好),而这里咱们之所以衔接蜂鸣器而不是按键,是因为蜂鸣器与LED一样都是显示器件,它与LED一样都是依赖简单的GPIO地O也就是OUTPUT输出功能,咱们先把这一类显示器件的使用归类到一起,让观者可以在共性的模板中更好的学习
(这里笔者的板子对应的蜂鸣器是P1的第5位)

#include<regx52.h>
sbit beep = P1^5;

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    while(1) {
        beep = !beep;   // 0响1停,P口引脚最开始默认输出1
        delay_ms(10);  // 控制节拍速度
    }
}

流水音乐会

好了,咱们已经熟悉了简单显示器件的使用,咱们来做个综合实验

#include<regx52.h>
sbit beep = P1^5;

void delay_ms(unsigned int n) {
    unsigned int i;
    while(n--) {
        for(i=0; i<280; ++i);
    }
}

int main() {
    unsigned int i;
    while(1) {
        for(i=0; i<8; ++i) {
            P2 = ~(1 << i); // 流水灯
            beep = !beep;           
            delay_ms(10);
            beep = !beep;          
            delay_ms(100);
        }
    }
}

总结

简单显示器件的使用都是大同小异,已经难不倒咱们了,于是接下来咱们要去学习一点比较困难的显示器件,它们可能需要的操作往往不局限在代码内,可能是翻阅数据手册,可能是计算进制数……

相关文章:

  • yarn调度过程
  • C++20 指定初始化器
  • 算是解决可以访问github但无法clone的问题
  • 【Java 优选算法】分治-归并排序
  • 代码随想录|二叉树|11完全二叉树的节点个数
  • spring-ai-alibaba-examples项目编译运行
  • 代码随想录算法训练营第七天|组合、组合总和III和电话号码的字母组合
  • 基于cat1的贵重物品的状态和位置小型监控系统特色解析
  • 第十五届蓝桥杯C/C++B组拔河问题详解
  • OrioleDB: 新一代PostgreSQL存储引擎
  • stl之string的详解
  • 基于云的内容中台驱动企业智能服务升级
  • 并发编程--具名管道
  • HarmonyOS-应用程序框架基础
  • 应用于电池模块的 Fluent 共轭传热耦合
  • 【源码分析】Nacos服务注册源码分析-客户端
  • 解决load()文件报错zipfile.BadZipFile: File is not a zip file
  • 给easygui添加字体设置功能(tyysoft增强版)
  • WEB UI自动化测试中,元素定位的八大定位方式详解
  • 事务与异步方法(@Async)协同工作
  • 央行副行长:增强外汇市场韧性,坚决对市场顺周期行为进行纠偏
  • 加拿大今日大选:房价、印度移民和特朗普,年轻人在焦虑什么?
  • 五一假期“热潮”来袭,计划南下的小伙伴注意了
  • 多家媒体及网红走进云南曲靖沾益:感受珠江源头
  • 大漠孤烟为何“直”?物理学家在唐诗中读出“不一样的美”
  • 第152次中老缅泰湄公河联合巡逻执法行动圆满结束