# 第三节:单片机最重要的一个特性
## 【3.1 单片机的 “一”】
![](https://img.kancloud.cn/ee/55/ee55481b13bed117d83fb7404caec983_506x321.png)
图 3.1 单片机工作的最小系统
“道生一,一生二,二生三,三生万物。”《道德经》认为,世间万物,缤纷多彩,都源自一个东西,这个 “一” 的东西就是 “道”。电子世界也存在 “一”,这个 “一” 繁衍出手机、电脑、电视机、机器人等丰富多彩的电子世界,这个 “一” 就是单片机最重要的一个特性:“程序下载进内存后,单片机既可以通过管脚识别外部输入的高低电平信号,也可以通过管脚对外部输出不同时间长度的高低电平。” 这句话有 5 个关键词 “程序、内存、管脚、电平、时间。” 下面我详细解读每个关键词的含义,涉及到某些专用名词如果不理解也没关系,主要是让大家有个感性的认识就足矣。
## 【3.2 程序】
单片机程序有 3 种:C 程序、汇编程序、机器程序。能下载进单片机的只有机器程序,C 程序和汇编程序都不能直接下载进单片机,所以 C 程序和汇编程序都要经过编译软件翻译成机器程序后,才能下载进单片机。程序是语言,语言是用来交流,交流就必须存在两个对象,对象分别是程序员和单片机。程序员是人所以用 C 或者汇编语言,单片机是机器所以用机器语言,人和机是不同的世界,两者交流就需要一个翻译家,翻译家就是编译软件,俗称编译器,它能把 C 语言或者汇编语言翻译成单片机能识别的机器语言。机器语言就是 0101 的代码,一般以十六进制的形式呈现。
理论上,程序员也可以抛开 C 和汇编语言,直接用机器语言做项目。我读书时老师让我们做实验就是这么整。那时我还不知有烧录器,老师让我们先用汇编语言写好程序,然后自己充当编译器,对照汇编语言和机器语言的指令表,人工把汇编语言翻译成十六进制的机器语言,最后把机器语言按字节一个一个的输入到特定的实验设备来观察现象。现在回想起来,老师当时的初衷是让我们了解编程语言的本质。
既然可以直接用机器语言做项目,为什么还要 C 语言或者汇编语言?在 C 语言或者汇编语言没有诞生前,程序员就是通过在纸带上打孔来代表 01 的机器语言,此时相当于结绳记事的原始阶段。后来人类发明了汇编语言,通过英语单词来表示 01 机器语言特定的指令语句,此时开始诞生了汇编语言的编译器相当于进入象形文字的阶段。再到后来人类又发明了 C 语言,通过数学符号和英语单词来表达自己的逻辑,诞生了 C 语言的编译器相当于进入了汉字白话文阶段,从此程序员写出来的 C 程序就非常方便移植,编辑,阅读,传播,继承。现在单片机开发的主流是 C 语言,我本人出来工作后就没有用过汇编做项目开发。C 语言是必修课,汇编语言是选修课;C 语言是白话文简单易懂,汇编语言是文言文繁琐难读。当然汇编也有它的应用场合,汇编的翻译效率高,往往是一句汇编语言对应一句机器语言,而一句 C 语言有可能对应几句机器语言,这样 C 程序的代码效率在很大程度上取决于编译器的水平,编译器能不能帮你翻译出高效的机器语言对于我们来说往往像黑盒子,不像汇编语言那么可控制。所以很多嵌入式系统某段要求简洁高效的源代码往往用汇编来写,也有少数一些很便宜的单片机不提供 C 编译器,只能用汇编语言开发。要不要学汇编,最好根据个人的工作需求来决定。
## 【3.3 内存】
单片机就像 MP3,程序代码就像歌曲,把不同的歌曲下载到 MP3 里就可以听到不同的音乐,把不同的程序下载到单片机里,单片机就能做不同的事。能装程序的单片机必然有内存,内存由 ROM 和 RAM 组成,ROM 和 RAM 都能装东西,但各有不同。
ROM 的优点是存储的东西断电后不会丢失,缺点是存储的东西上电后不能更改,想要改变 ROM 的内容除非重新下载程序,而且下载次数有限制,FLASH 的 ROM 最大次数通常是 10 万次,而 OTP 的 ROM 只能下载 1 次,所以平时上电工作时 ROM 存储的东西是不能更改的,某些具有 IAP 功能的高级单片机不在此讨论范围内。而 RAM 恰好反过来,RAM 的优点是存储的东西上电后可以随时被单片机更改,更改次数没有限制,缺点是存储的东西断电后会丢失,没有记忆功能。
ROM 和 RAM 各有特点,单片机从中各取所长。ROM 用来存储不可更改的指令代码和常量数据,ROM 的容量往往相当于代码的容量。RAM 用来存储可以被更改的变量数据,RAM 的容量往往相当于全局变量和局部变量的容量。不管是用 C 语言还是汇编,所写的程序代码就自然包含了指令代码、常量数据、全局变量、局部变量,那么谁在幕后帮我们进行分类存储,谁把一个程序代码的一分为二让它们在 ROM 和 RAM 里各就各位?是编译器软件和下载器 (烧录器),编译器除了把 C 语言翻译成机器语言之外,还帮我们分好了类,分配好了存储的地址和位置,下载器 (烧录器) 再根据这些信息把程序存储到内存中,这些工作一般不用程序员干预,它们自动完成。
## 【3.4 管脚】
管脚是单片机与外部电路进行能量和信息交互的桥梁。有电源,复位,晶振和 IO 口这 4 类管脚。
第一类电源管脚。是给单片机内部电路供电的接口。单片机有两种常用的供电电压,一般是 3.3V 或者 5V,有的单片机两种电压都兼容。
第二类复位管脚。单片机上电后需要外部电路给它一个瞬间高电平或者低电平的复位信号,才能启动工作。复位电路通常是由电容和电阻组成的充电电路来实现,也有一些系统是用专门的复位芯片来实现。
第三类晶振管脚。任何单片机想要工作必须要有晶振。单片机执行程序指令是按一个节拍一个节拍来执行的。这个节拍的时间就是由晶振产生,所以把晶振比喻成单片机的心脏是非常恰当的。现在也有很多单片机直接把晶振集成到内部,这类单片机不用外接晶振也可以。
第四类 IO 口管脚。这是跟我们编写程序关联最密切的管脚。前面提到的电源,复位,晶振这 3 种管脚是为了让单片机能工作,俗称单片机工作的三要素。而单片机工作的具体内容就是通过 IO 口管脚来体现的。比如,IO 口能识别按健的输入,也能输出驱动继电器工作的开关信号,也能跟外围器件进行通信。
## 【3.5 电平】
电平就是电压的两种状态,低或者高,低相当于程序里的 0,高相当于程序里的 1。单片机 IO 口管脚检测到的电压低于或等于 0.8V 时是低电平,程序里读取到的是 0 数字。单片机 IO 口管脚检测到的电压高于或等于 2.4V 时是高电平,程序里读取到的是 1 数字。必须注意的是,IO 口输入的最大电压不能超过单片机的供电电压。单片机输出的低电平是 0V,单片机输出的高电平等于它的供电电压值,往往是 3.3V 或者 5V。
## 【3.6 时间】
时间是单片机程序必不可少的元素。跟外围芯片通信的时序节拍需要时间,驱动发光二极管闪烁需要时间,工控自动化的某些延时需要时间。单片机的时间来源自两方面。第一方面源自指令的周期时间。单片机是根据节拍来执行程序指令的,每执行一条指令都要消耗一点时间,只要让程序执行的指令数量越多,产生的时间就越长,通过调整所执行指令的数量就可以得到所需的时间长度。第二方面源自单片机内部自带的定时器。假如设置定时器每 20 毫秒产生一次中断,现在要获取 10 秒钟的时间,只需在程序里统记 500 次定时中断就可以了,因为 1 秒等于 1000 毫秒。指令和定时器这两者的时间最后都来源于晶振。
- 首页
- 第一节:我的价值观
- 第二节:初学者的疑惑
- 第三节:单片机最重要的一个特性
- 第四节:平台软件和编译器软件的简介
- 第五节:用Keil2软件关闭,新建,打开一个工程的操作流程
- 第六节:把.c源代码编译成.hex机器码的操作流程
- 第七节:本节预留
- 第八节:把.hex机器码程序烧录到单片机的操作流程
- 第九节:本节预留
- 第十节:程序从哪里开始,要到哪里去?
- 第十一节:一个在单片机上练习C语言的模板程序
- 第十二节:变量的定义和赋值
- 【TODO】第十三节:赋值语句的覆盖性
- 【TODO】第十四节:二进制与字节单位,以及常用三种变量的取值范围
- 【TODO】第十五节:二进制与十六进制
- 【TODO】第十六节:十进制与十六进制
- 【TODO】第十七节:加法运算的5种常用组合
- 【TODO】第十八节:连加、自加、自加简写、自加1
- 【TODO】第十九节:加法运算的溢出
- 【TODO】第二十节:隐藏中间变量为何物?
- 【TODO】第二十一节:减法运算的5种常用组合。
- 【TODO】第二十二节:连减、自减、自减简写、自减1
- 【TODO】第二十三节:减法溢出与假想借位
- 【TODO】第二十四节:借用unsigned long类型的中间变量可以减少溢出现象
- 【TODO】第二十五节:乘法运算中的5种常用组合
- 【TODO】第二十六节:连乘、自乘、自乘简写,溢出
- 【TODO】第二十七节:整除求商
- 【TODO】第二十八节:整除求余
- 【TODO】第二十九节:“先余后商”和“先商后余”提取数据某位,哪家强?
- 【TODO】第三十节:逻辑运算符的“与”运算
- 【TODO】第三十一节:逻辑运算符的“或”运算
- 【TODO】第三十二节:逻辑运算符的“异或”运算
- 【TODO】第三十三节:逻辑运算符的“按位取反”和“非”运算
- 【TODO】第三十四节:移位运算的左移
- 【TODO】第三十五节:移位运算的右移
- 【TODO】第三十六节:括号的强制功能---改变运算优先级
- 【TODO】第三十七节:单字节变量赋值给多字节变量的疑惑
- 【TODO】第三十八节:第二种解决“运算过程中意外溢出”的便捷方法
- 【TODO】第三十九节:if判断语句以及常量变量的真假判断
- 【TODO】第四十节:关系符的等于“==”和不等于“!=”
- 【TODO】第四十一节:关系符的大于“>”和大于等于“>=”
- 【TODO】第四十二节:关系符的小于“<”和小于等于“<=”
- 【TODO】第四十三节:关系符中的关系符:与“&&”,或“||”
- 【TODO】第四十四节:小括号改变判断优先级
- 【TODO】第四十五节: 组合判断if...else if...else
- 【TODO】第四十六节: 一维数组
- 【TODO】第四十七节: 二维数组
- 【TODO】第四十八节: while循环语句
- 【TODO】第四十九节: 循环语句do while和for
- 【TODO】第五十节: 循环体内的continue和break语句
- 【TODO】第五十一节: for和while的循环嵌套
- 【TODO】第五十二节: 支撑程序框架的switch语句
- 【TODO】第五十三节: 使用函数的三要素和执行顺序
- 【TODO】第五十四节: 从全局变量和局部变量中感悟“栈”为何物
- 【TODO】第五十五节: 函数的作用和四种常见书写类型
- 【TODO】第五十六节: return在函数中的作用以及四个容易被忽略的功能
- 【TODO】第五十七节: static的重要作用
- 【TODO】第五十八节: const(./book/或code)在定义数据时的作用
- 【TODO】第五十九节: 全局“一键替换”功能的#define
- 【TODO】第六十节: 指针在变量(./book/或常量)中的基础知识
- 【TODO】第六十一节: 指针的中转站作用,地址自加法,地址偏移法
- 【TODO】第六十二节: 指针,大小端,化整为零,化零为整
- 【TODO】第六十三节: 指针“化整为零”和“化零为整”的“灵活”应用
- 【TODO】第六十四节: 指针让函数具备了多个相当于return的输出口
- 【TODO】第六十五节: 指针作为数组在函数中的入口作用
- 【TODO】第六十六节: 指针作为数组在函数中的出口作用
- 【TODO】第六十七节: 指针作为数组在函数中既“入口”又“出口”的作用
- 【TODO】第六十八节: 为函数接口指针“定向”的const关键词
- 【TODO】第六十九节: 宏函数sizeof(./book/)
- 【TODO】第七十节: “万能数组”的结构体
- 【TODO】第七十一节: 结构体的内存和赋值
- 【TODO】第七十二节: 结构体的指针
- 【TODO】第七十三节: 结构体数据的传输存储和还原
- 【TODO】第七十四节: 结构体指针在函数接口处的频繁应用
- 【TODO】第七十五节: 指针的名义(例:一维指针操作二维数组)
- 【TODO】第七十六节: 二维数组的指针
- 【TODO】第七十七节: 指针唯一的“单向输出”通道return
- 【TODO】第七十八节: typedef和#define和enum
- 【TODO】第七十九节: 各种变量常量的命名规范
- 【TODO】第八十节: 单片机IO口驱动LED
- 【TODO】第八十一节: 时间和速度的起源(指令周期和晶振频率)
- 【TODO】第八十二节: Delay“阻塞”延时控制LED闪烁
- 【TODO】第八十三节: 累计主循环的“非阻塞”延时控制LED闪烁
- 【TODO】第八十四节: 中断与中断函数
- 【TODO】第八十五节: 定时中断的寄存器配置
- 【TODO】第八十六节: 定时中断的“非阻塞”延时控制LED闪烁
- 【TODO】第八十七节: 一个定时中断产生N个软件定时器
- 【TODO】第八十八节: 两大核心框架理论(四区一线,switch外加定时中断)
- 【TODO】第八十九节: 跑马灯的三种境界
- 【TODO】第九十节: 多任务并行处理两路跑马灯
- 【TODO】第九十一节: 蜂鸣器的“非阻塞”驱动
- 【TODO】第九十二节: 独立按键的四大要素(自锁,消抖,非阻塞,清零式滤波)
- 【TODO】第九十三节: 独立按键鼠标式的单击与双击
- 【TODO】第九十四节: 两个独立按键构成的组合按键
- 【TODO】第九十五节: 两个独立按键的“电脑键盘式”组合按键
- 【TODO】第九十六节: 独立按键“一键两用”的短按与长按
- 【TODO】第九十七节: 独立按键按住不松手的连续均匀触发
- 【TODO】第九十八节: 独立按键按住不松手的“先加速后匀速”的触发
- 【TODO】第九十九节: “行列扫描式”矩阵按键的单个触发(原始版)
- 【TODO】第一百节: “行列扫描式”矩阵按键的单个触发(优化版)
- 【TODO】第一百零一节: 矩阵按键鼠标式的单击与双击
- 【TODO】第一百零二节: 两个“任意行输入”矩阵按键的“有序”组合触发
- 【TODO】第一百零三节: 两个“任意行输入”矩阵按键的“无序”组合触发
- 【TODO】第一百零四节: 矩阵按键“一键两用”的短按与长按
- 【TODO】第一百零五节: 矩阵按键按住不松手的连续均匀触发
- 【TODO】第一百零六节: 矩阵按键按住不松手的“先加速后匀速”触发
- 【TODO】第一百零七节: 开关感应器的识别与软件滤波
- 【TODO】第一百零八节: 按键控制跑马灯的启动和暂停和停止
- 【TODO】第一百零九节: 按键控制跑马灯的方向
- 【TODO】第一百一十节: 按键控制跑马灯的速度
- 第一百一十一节: 工业自动化设备的开关信号的运动控制
- 【TODO】第一百一十二节: 数码管显示的基础知识
- 【TODO】第一百一十三节: 动态扫描的数码管显示数字
- 【TODO】第一百一十四节: 动态扫描的数码管显示小数点
- 【TODO】第一百一十五节: 按键控制数码管的秒表
- 【TODO】第一百一十六节: 按键控制数码管的倒计时
- 【TODO】第一百一十七节: 按键切换数码管窗口来设置参数
- 【TODO】第一百一十八节: 按键让某位数码管闪烁跳动来设置参数
- 【TODO】第一百一十九节: 一个完整的人机界面的程序框架的脉络
- 【TODO】第一百二十节: 按键切换窗口切换局部来设置参数
- 【TODO】第一百二十一节: 可调参数的数码管倒计时
- 【TODO】第一百二十二节: 利用定时中断做的“时分秒”数显时钟
- 【TODO】第一百二十三节: 一种能省去一个lock自锁变量的按键驱动程序
- 【TODO】第一百二十四节: 数显仪表盘显示“速度、方向、计数器”的跑马灯
- 【TODO】第一百二十五节: “双线”的肢体接触通信
- 【TODO】第一百二十六节: “单线”的肢体接触通信
- 【TODO】第一百二十七节: 单片机串口接收数据的机制
- 【TODO】第一百二十八节: 接收“固定协议”的串口程序框架
- 【TODO】第一百二十九节: 接收带“动态密匙”与“累加和”校验数据的串口程序框架
- 【TODO】第一百三十节: 接收带“动态密匙”与“异或”校验数据的串口程序框架
- 【TODO】第一百三十一节: 灵活切换各种不同大小“接收内存”的串口程序框架
- 【TODO】第一百三十二节:“转发、透传、多种协议并存”的双缓存串口程序框架
- 【TODO】第一百三十三节:常用的三种串口发送函数
- 【TODO】第一百三十四节:“应用层半双工”双机串口通讯的程序框架