数字电路与单片机C编程杂谈

控制/MCU

1877人已加入

描述

1、电平

计算机只能识别0和1,单片机作为计算机的一种,它也只能识别0和1。0和1是用来描述两种状态的,比如,有和无,大和小,胖和瘦,高和矮。

在数字电路里, 我们用两段电压范围来表示0和1 。比如,0V到0.7V表示0,3V到3.3V表示1。在这里,0和1表示的是一个电压范围,因此,0和1称之为电平,0称为低电平,1称之为高电平。这个电压范围是多大,我们在单片机数据手册里可以查询到。

2、进制

数制是人们利用符号进行计数的科学方法。数制有很多种,常用的数制有:二进制,十进制和十六进制。

进位计数制是把数划分为不同的位数,逐位累加,加到一定数量之后,再从零开始,同时向高位进位。进位计数制有三个要素:数码符号、进位规律和计数基数。下表是各常用数制的总体介绍。

BCD码

关于这三种进制的转换,学习者自行查看相关课本或者百度去学习一下。这里,我只举几个例子:

(137)D = 110^2 + 310^1 + 710^0 = 137; (137)H = 116^2 + 316^1 + 716^0 = 311; (10011010)B = 12^7 + 02^6 + 02^5 + 12^4 + 12^3 + 02^2 +12^1 +02^0 =2^7 + 2^4 +2^3 + 2^1 = 128+16+8+2 = 154

二进制一般不会直接转成十进制,因为太麻烦了。一般是把二进制先转成十六进制,再把十六进制转成十进制,举个例子: (10011010)B = (9A)H = 9*16+10 =154

这里提一下著名的BCD码,又称为8421码。二进制与十六进制转换的思路是,每4位二进制转成1位十六进制。(1111)B=2^3+2^2+2^1+2^0=8+4+2+1=15=F,4位二进制能表示的最大值是15,刚好对应十六进制的最大数字F,所以每4位二进制可以表示1位十六进制。实际上,在单片机编程中,10进制与16进制是用的最多的。

3、逻辑运算符与位运算

&& :逻辑与,同时满足的意思。 比如A&&B,A和B同时为真,那么这个表达式就为真。假用0表示,真即为非0。在单片机编程中,通常用在if语句里来判断几个条件是否同时成立。

BCD码

& :按位与,每一位进行与运算,对应的位同时为1时,位结果才为1。

比如 1101 0011B & 0110 1101B

1 1 0 1 0 0 1 1                                                & 0 1 1 0 1 1 0 1                                                = 0 1 0 0 0 0 0 1

按位与运算常用来判断标志位,比如定义一个8位flag,每一位可以定义为某个特殊的标志位,比如按键长按标志位,长按为1,短按为0。那么按键处理程序就可以通过判断flag的某一位是否为1来判断是否为长按。

|| :逻辑或,是指要么条件A发生,要么条件B发生。多个条件只要有一个条件满足,那么整个表达式就为真。||通常用在if语句里,用来判断某些事件是否发生。

BCD码

龙虾哥如果在吃饭或者在上班,那么,龙虾哥就不会在群里说话。没有吃饭也没有上班时,就会来群里吹牛。

|: 按位或,是指每一位进行或运算。

在单片机里经常这样使用 A |=0x01; A的最低位置1,其他位不变。

~ :按位取反,取反就是原来是0,那么现在就为1,原来为1现在就为0。

~ 通常和 & 一起使用,用来对某一位进行清0操作。**A &= ~0x01; **A的最低位被清0。

! :非,不是的意思。常用于按键检测判断是不是按下。假设按键按下时,单片机的IO为低电平。则可以这样判断:

BCD码

<<左移,往左移动的意思。在无符号整型变量中左移一位相当于乘2。

比如,8*2等效8<<1。

>>右移,往右移动的意思。在无符号整型变量中右移一位相当于除2。

比如,8/2等效8>>1。

** <<** 还有一种常见的用法就是,寄存器编程时,用来设置某一位1,使能某位的意思。寄存器R定义为16位,那么,R的第8位置1,我们可以这样写R |= 1<<8;假设第8位是某个功能的使能位,我们可以进一步这样写:

#define ENABLE (1<<8)

#define DISABLE ( ~(1<<8) )

R |= ENABLE;

R &= DISABLE;

通过这种方法,我们就不需要去记忆R的每一位是什么意思了。通过宏定义**#define**把寄存器的每一位取个名字,这样我们使用时,通过名字来赋值,更容易记忆和编写程序,这种思路就是库编程的早期思想,所以,我前面提过不要过于纠结用库还是寄存器编程,其实没啥区别,都是一样的思路。

** >>和<<** 还用于单片机与外设通信里,比如通过io传递8位数据,低位先传输,我们可以这样写。

BCD码

高位先传输,我们可以写成这样:

BCD码

4、C语言常用的逻辑结构与多文件编程程序框架

C语言编程的一大特色就是模块化编程,我们通常把单片机外部电路的驱动程序写成模块的形式。这个模块一般由多个函数组成,一个外设驱动程序一般包含一个C文件和一个头文件。

头文件XXXX.H里面编写函数的声明以及一些宏定义,而C文件编写函数的定义。举个例子:

XXXX.H文件 / XXXXX外设驱 *

这里面描述驱动程序的一些说明以及注意事项

编写者,版本号,修改人,日期等信息

*******************************************/

#ifndef __XXXX_H

#define __XXXX_H

#define ON 1

#define OFF 0

#define SET 1

#define RESET 0

void XXXX_WriteData(uint8_t data);

uint8_t XXXX_ReadData(void);

#endif

XXXX.c文件

/******************************************

C文件函数的相关说明

******************************************/

BCD码

​如果一个函数,在其他文件中不使用,只在本驱动文件内部使用的,那么要在这个函数前面加static,比如:

BCD码

​在其他文件中需要调用驱动函数时,只需要加入#include “XXXX.H”这句话就可以了。比如在main.c文件中:

BCD码

几种常见的逻辑结构

BCD码

BCD码

switch case常用于菜单和多条件判断,比如按键检测的处理。每个按键都有对应的按键值,通过按键值的逐一比对,就可以实现按键对应值得处理。

BCD码

5、变量的生存期与作用域

在函数内部定义的变量叫作局部变量,否则叫作全局变量。

变量的作用域是指变量起作用的范围,在这个范围内,才能使用这个变量。

全局变量的作用域为从变量定义开始到文件结束。当全局变量与局部变量重名时,在函数内部以局部变量为主。

变量的生存期是指,变量存在的时间范围。比如,全局变量定义后,在整个程序执行期间都一直存在。局部变量是在函数内部存在,当函数开始执行时,局部变量开始被创建,当函数执行结束时,局部变量就消失不存在了。

在其他文件中,在全局变量前面加extern,可以拓展全局变量的作用域。

比如,在文件A中: int a=8;在B文件中可以这样写:extern int a;这样子就可以在B文件中使用变量a了。

如何拓展局部变量的生存期?只需要在变量前加static就可以了。为什么要拓展局部变量的生存期呢?因为,我们经常需要局部变量一直存在,但是,我们又不想变量被外部程序改变。因此,我们需要一个一直存在的局部变量。比如,在按键检测中,为了消抖且不长时间堵塞,我们常常写成下面这种形式。

BCD码

BCD码

这里循环10000次,相当于200MS滤波消抖,如果直接200MS延迟滤波会耽误其他程序执行。

C语言主要掌握的内容就是数据类型,变量的生存期以及作用域,逻辑运算符,分支语句结构,数组,函数,宏定义,结构体,一维指针。这些内容最好熟悉了后,再学习单片机比较好,这样你看别人程序也能看懂,自己写程序也不会犯错。如果不熟悉这些,那么你自己看别人程序会一知半解,自己写程序也写不好,反而耽误时间以及打击自信心。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分