扫盲教程:深入浅出讲解单片机控制单只数码管循环显示0~F
最近有好多小伙伴留言说,我发的项目很难,他们都是刚入门的,希望我写一些入门级的教程,那么今天我就从硬件和软件两个方面来给大家讲一下最基本也是十分重要的电路 单片机驱动数码管显示电路。
要弄清楚单片机控制数码管显示字符的原理我们首先要知道:三个概念
单片机:通俗的讲单片机是一种集成电路芯片,利用一些特殊工艺把许多不同功能的模块集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。单片机可以烧进程序,然后从不同的IO口输出规定的电平信号。
七段数码管(如下图):
数码管是一类价格便宜 使用简单,通过对其不同的管脚输入相对的电流,使其发亮,从而显示出数字能够显示 时间、日期、温度等所有可用数字表示的参数的器件。一般的七段数码管拥有七个发光二极管(三横四纵)用以显示十进制0至9的数字外加小数点,也可以显示英文字母 A 至 F(b、d 为小写,其他为大写)。现时大部分的七段数码管会以斜体显示。
好了,上面是单片机和数码管的概念,下面说一下单片机的工作原理:
一个单片机要想能正常工作必须满足它工作的最小系统,这个最小系统包括,电源电路,晶振电路,复位电路等,当电源电路给单片机正常供电后,在上电的一瞬间会给复位电容充电从而完成上电复位的动作。单片机复位结束后,我们把需要控制数码管显示的代码烧进单片机,这时候单片机就会根据写的代码从不同的IO口输出不同的电平,从而控制七段数码管每一段的亮灭,而达到显示不同数字的目的。
好了说了半天理论了,下面我们开始实践一下吧!
首先用PROTEUS仿真软件画好单片机最小系统和LED数码管驱动原理图:本项目中用STC89C52
把程序烧进去以后,数码管开始从0到F显示,适当调整源代码参数可以修改显示不同的数字和不同的时间间隔。
51单片机参考源代码如下:
/*单只数码管循环显示0~F 作者 科技小伟1*/
#include <reg51.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
code uint8 LED_CODE[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xA7,0xA1,0x86,0x8E};
void delay(uint16 x)
{
uint16 i,j;
for(i = x; i > 0; i --)
for(j = 114; j > 0; j --);
}
void main()
{
uint8 i = 0;
while(1)
{
for(i = 0; i < 16; i ++) //i = (i + 1) % 16
{
P0 = LED_CODE[i];
delay(500);
}
}
}
好了以上就是单片机控制数码管显示的全部内容了,本文从软件和硬件两个角度分别讲解,如果有任何意见或者需要设计文件 欢迎留言或者私信,如果你也对单片机感兴趣,那么快点行动起来吧!我们下期再见!
看完这篇,轻松弄懂STM32 C语言变量的定义和初始化
我们今天探讨C语言变量的定义和初始化。那么我们首先要明确三个问题。第一,我们要明白什么是变量,或者为什么C语言一定要有变量;第二个在C语言中如何去表达这些变量,或者说C语言都有什么类型的变量如何定义这些变量;第三,变量为什么要初始化,以及如何初始化。
第一个问题,关于变量,一个最通俗的理解就是变化的量。本来外在的物质世界就是在不断变化的,不是有句话么:“唯一不变的就是变化”。C语言作为描述客观世界变化的一种语言,首先就是要有能够对外界事物变化状态量化的工具,那么这个工具就是变量。数字世界,首先就是量化,这个是一切后续工作的基础。
我们下面拿几个常用的变量类型进行说明,比如char型变量,它主要是用来应对0 – 255之间变化的事物的,比如字符什么的。比如float,浮点型的变量,它主要是量化客观世界中模拟量的事物,比如汽车的速度、太阳光的强度等等;再比如int型的变量,它的描述范围就比char型大得多了,它主要是应对整数变化的客观事物的,比如学生的个数、苹果的个数等等。
那么实际上,我们说C语言的变量远不止这些简单的数据类型,是吧。我们还有数组,结构体,还有指针、栈、链表等等。每种数据类型的出现都是为了解决一个量化的问题,比如指针,它主要是定位量化计算机中内存寻址问题;比如结构体,它的定位主要是用来描述复杂事物的,就比如汽车,它不仅有行驶的速度,还有轮子的个数,椅子的个数等等;再比如栈,它的主要作用是解决任务切换以及函数调用时,程序现场的保护问题。
那么也就是说每一个变量类型或者量化工具类型的出现,都是有原因的,都是为了解决实际问题的。当我们从这个视角去看这些变量类型和必要性的时候,我们的理解就会深刻很多。举个例子,比如面向对象数据类型的产生,就是把方法或者函数集成到了一个类型中,这样就可以更为准确的去描述客观事物,比如一个狗狗,它不仅有一条大尾巴,还可以跑得非常快,大尾巴是数据,会跑且跑得快是方法。面向对象的语言比如C++或者Java,就把这些变量和方法封装起来,形成一个新的更为综合的量化工具,那就是对象。
站在C语言的基础上,往上看是C++语言等面向对象的,但是如果往下看,比如到了汇编级别,就是另外一番场景。我们知道汇编语言是最接近机器的语言,对于某一类型的单片机,它一般有几十条特定中汇编指令。但是我们说汇编语言是没有数据类型的,它操作的只有二进制类型的数据,并没有对这些数据进行按照其属性进行分类。没有根据属性对数据进行分类,其实也就是说没有对量化工具进行分类,那么人类的大脑就要耗费更多的能量去理解汇编程序,人的大脑本身都是很懒的,能省能量肯定是想办法节省能量。从这个角度上的看,汇编语言更像是机器语言。
但是我们说电脑本身就是机器,不同汇编语言的指令集才能真正反映各个芯片架构的不同,指令集不同可能对应的电路也是不同的。任何高级语言最后还是要在特定的机器上运行的,那也就是说这些高级语言最后还是要翻译成特定的汇编语言。这个翻译的工作就是编译器要做的事情。另外,软件的开发还要有量好的代码编辑环境以及调试环境(比如支持单步调试,实时查看寄存器及存储单元的数据),所以一款新的单片机是不是好用会有多方面的因素影响的,也不能只看指令集的执行效率。
第二个问题,C语言都有什么类型的变量呢?我们可以用一张表来大概描述一下,下面这张表对C语言的数据类型进行了相对完整的总结。大家可以看一下,整体的数据类型被划分为四类:基本类型,构造类型(组合类型),指针类型还有空类型。基本的数据类型肯定是根本,C语言在级别数据类型的基础上构造出更为复杂的数据类型,用于描述相对复杂的事物,比如结构体等等。那么C语言就是使用这些相对抽象的基本类型,去量化和描述纷繁复杂的外部世界的。我们在前面已经提到了绝大多数数据类型产生的原因,这里就不再赘述了。如果有还不理解的同学,可以自己上网去查一查资料。
从下面这幅图可以看出,不同的基础数据类型器长度是不一样的,而且同一种数据类型在不同的机器和编译器编译下其数据长度也是不一样的。不同的基础数据类型,所占据是二进制数据位数发生不同,这个是可以理解的。对于相对简单的事物,比如字符,本来就不需要使用那么长的位数来表达,这个是基本诉求。再一个,比如对于char类型这种需要较少位数就可以表达的可以量化的事物,如果使用int这种长度的数据去表达,本身也是对计算机存储资源的浪费。基于上述两个原因,才出现了不同的数据类型有不同的长度的现象。我们在实际编程的时候,从设计的角度上来看,肯定是选择使用最少的存储位数来量化自己要描述的事物,这样占用的资源才能是最少。当程序代码行数非常多的时候,这种差异就会相对非常明显了。
下面,我们来探讨第三个问题,变量为什么要初始化以及如何初始化。我们首先解释一下为什么单片机数据最好要初始化。众所周知,变量是存储在RAM中,掉电后即丢失,上电后默认全为0。那么这样的话没赋初值的变量值全为0,这也应该是大家认为理所当然的。但是实际上并不是这样,有些类型的单片机,当单片机复位的时候(包括硬件复位即按下复位按钮,看门狗复位,以及其它软件程序复位),单片机只是重新跳回到main函数开始执行,而并没有清空RAM!所以,那些只是定义而没有赋初值的变量(尤其是全局变量)依然会使用复位前留下来的值!那么这样,程序运行可能就会出现异常的结果,尤其是指针变量。数据有一个初始的值,整个程序也就有了一个初始状态,初始状态确定了,如果程序设计得没有问题,那么就可以按照既定的规则跑下去。如果程序错误发生在初始位置上,那就太可惜了。大家在编程的时候,一定要注意这个现象。
那么下面我们看一下,如何对变量进行初始化。不同的变量类型,初始化的方式肯定是不一样的。首先对于基础的数据类型,可以直接初始化成想要的值即可。那么对于数组、结构体等类型,初始化的方法就具体问题具体分析,各具特色了。我们下面举例子进行说明。
一维数组:
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int a[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int a[10] = {0};
int a[] = {1, 2, 3, 4, 5};
二维数组:
int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int a[3][4] = {{1}, {5}, {9}};
/*
1 0 0 0
5 0 0 0
9 0 0 0
*/
int a[3][4] = {{1}, {0, 6}, {0, 0, 11}};
/*
1 0 0 0
0 6 0 0
0 0 11 0
*/
int a[3][4] = {{1}, {5, 6}};
/*
1 0 0 0
5 6 0 0
0 0 0 0
*/
int a[][4] = {{0, 0, 3}, {}, {0, 10}};
/*
0 0 3 0
0 0 0 0
0 10 0 0
*/
字符数组:
char c[10] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};
char c[2][3] = {{'y', 'o', 'u'}, {'a', 'r', 'e'}};
char c[] = {"I am happy"};
char c[] = "I am happy"; // 可以省略花括号
char c[] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y', ''}; // 与上面等价
char *p;
p = "I love China"; // 正确
char c[14];
c = "I love China"; // 错误
c[14] = "I love China"; // 错误
结构体:
struct {
char name[20];
int age;
}student1, student2;
//匿名结构体
struct Student {
char name[20];
int age;
}student1, student2;
//声明结构体
struct Student {
char name[20];
int age;
}student1 = {"xiaoming", 20};
struct Student student1={.age=12}; // C99可以只对age进行初始化,其他变量初始化成零
联合体:
union Data {
int i;
char ch;
float f;
}a = {1, 'a', 1.5}; // 错误,不能同时初a.ch = 'A'; // 正确
对共用体赋值要指明赋值对象,如
a.f = 1.5; // 正确
a.i = 40; // 正确
a = 1; // 错误,没有指明赋值对象始化3个
union Data a = {16}; // 正确
union Data a = {.ch='j'}; // 正确 C99新增
枚举:
第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。
声明
enum Weekday {sun, mon, tue, wed, thu, fri, sat};
定义
enum Weekday workday, weedkend;
赋值
enum Weekday {sun=7, mon=1, tue, wed, thu, fri, sat};
// sun=7, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6
把上述三个问题到搞清楚后,我们的这篇文章到此就结束了。
参考资料
(复制链接在浏览器打开)
① C语言数据类型总结
https://blog.csdn.net/xingjiarong/article/details/46942649
② C++继承
https://www.runoob.com/cplusplus/cpp-inheritance.html
③单片机C语言探究--为什么变量最好要赋初值
https://blog.csdn.net/weixin_34342207/article/details/92999746
④ C语言-定义与初始化总结
https://blog.csdn.net/syzdev/article/details/103532435
相关问答
单片机 中 INT0 ,EX0,ET0,IE0.分别表示什么意思?外部中断0、外部中断0的中断允许控制位、timer的中断控制位、INT1的中断请求标志郭天祥的应用手册里有,希望对你有帮助外部中断0、外部中断0的中断允...
c51 单片机 怎样用 int0 编程紧急制动按钮?一只10uF左右的电解电容和一只100nF...这需要在硬件和软件两个方面作处理。硬件上要将按钮的一端接地,另外一端通过10k左右的电阻上拉到电源Vcc,在按钮上还要...
单片机 常见故障及处理?一些单片机常见问题的解决办法工作和生活中会遇到许许多多的问题,可能让你一时陷于其中,但是总有解决的办法。随时记下遇到的问题,并做好总结,一方面有助于积...
单片机 试题解答1.当CPU响应外部中断0后,PC的值是(A)A.0003HB...[最佳回答]一,选择题1.当CPU响应外部中断0后,PC的值是(A)A.0003HB.2000HC.000BHD.3000H2.当MCS-51复位时,下面说法准确的是(A)A.PC=0000HB....
单片机 exo是什么意思?应该是EX0吧。EX0(IE.0):外部中断INT0的中断允许EX0=1打开外部中断应该是EX0吧。EX0(IE.0):外部中断INT0的中断允许EX0=1打开外部中断
89s51 单片机 有哪几个中断源?对应的中断入口地址是什么?AT89S51共有5个中断向量:2个外中断(INT0和INT1),2个定时中断(Timer0和Timer1)和一个串行中断。中断入口地址如下:外部中断INT00003H定时器0...AT89...
单片机 中void delay(unsigned int time)是什么意思?自定义的一个delay函数,一般是延时用void代表函数没有返回值unsignedint是定义的time类型,为无符号整形16位。time就是自定义参数自定义的一个delay函数,一般...
单片机 中#define uint unsigned int 这个宏定义是干什么用的,我发现删除也可以,那为什么要写上?它的作用是指定uint来代替unsignedint。在编写源程序时,所有的unsignedint都可由uint代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用unsignedi...
51 单片机 中C语言 int 能转换为字符串类型吗?怎么转换?1、可以转换,强制转换就行。例如:inta=100;unsignedchar*c=(unsignedchar*)a;2、强制类型转换当操作数的类型不同,而且不属于基本数据类型时,经常...
int a数组占用几个字节?一般而言,变量赋值后才可以有效使用。微机中(单片机)2个字节。inta;表示声明一个值。可以是无符号整型(整数)变量,其值最大是65535。可以是有符号整形可...