c语言模块化编程实现思路设计代码
具体的程序实现代码如下所示
1:程序的头文件
2:程序的函数文件
3:程序的主文件控制函数的实现
led 介绍
单片机的工作原理:cpu通过配置寄存器控制我们的硬件电路实现我们的功能
二进制转换为16进制:进制转换关系对应表
二进制转换16进制网址
点亮51单片机的第一个led灯和让单片机的led灯实现亮灭亮灭的效果(采用16进制的方式实现)
目前我使用的是清翔电子的51单片机(建议按照自己购买的单片机观看对应的学习视频)
led灯单个亮灭效果代码如下所示该单片机led灯的口为P1
#include
// P1 是第一个led晶体管1111 1110 倒数转换为16进制
void main(){
P1 = 0xFE; // 点亮第一个单片机的led灯
P1 = 0x55; // 单片机的亮灭效果
while(1){// 添加while循环让单片机停止或者开始
}
}
实现led灯的闪烁效果:编写延迟函数的方式
#include
#include
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
while(1){// 循环实现led灯的亮灭情况
P1 = 0xFE;
Delay500ms();// 函数的调用
P1 = 0xFF;
Delay500ms();
}
}
led的流水灯显示
#include
#include
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
while(1){// 循环实现led灯的亮灭情况
P1 = 0xFE; // 1111 1110
Delay500ms();
P1 = 0xFD; // 1111 1101
Delay500ms();
P1 = 0xFB; // 1111 1011
Delay500ms();
P1 = 0xF7; // 1111 0111
Delay500ms();
P1 = 0xEF; // 1110 1111
Delay500ms();
P1 = 0xDF; // 1101 1111
Delay500ms();
P1 = 0xBE; // 1011 1111
Delay500ms();
P1 = 0x7F; // 0111 1111
Delay500ms();
}
}
使用函数实现200毫秒轮动的流水灯
#include
#include
void Delay500ms(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
void main(){
while(1){
// 循环实现led灯的亮灭情况
P1 = 0xFE; // 1111 1110
Delay500ms(200); // 自定义200毫秒
P1 = 0xFD; // 1111 1101
Delay500ms(200);
P1 = 0xFB; // 1111 1011
Delay500ms(200);
P1 = 0xF7; // 1111 0111
Delay500ms(200);
P1 = 0xEF; // 1110 1111
Delay500ms(200);
P1 = 0xDF; // 1101 1111
Delay500ms(200);
P1 = 0xBE; // 1011 1111
Delay500ms(200);
P1 = 0x7F; // 0111 1111
Delay500ms(200);
}
}
2.1独立按键介绍
独立按键原理图
2.2独立按键控制led亮灭同时使用延时的方式防止抖动的出现
#include
#include
void Delay500ms(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
void main(){
while(1){
if(P3_0 == 0){
P1_0 = 0;
Delay500ms(500);
}else{
P1_0 = 1;
Delay500ms(500);
}
}
}
每次按下一次led取反显示:独立按键控制LED显示二进制(也就是按位取反)
#include
#include
void Delay500ms(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
// P3_0 表示的是第一个独立按键
// P1_0 表示的是第一个led灯
void main(){
unsigned char LEDNum = 0;
while(1){
if(P3_1 == 0){
Delay500ms(20);
while(P3_1 == 0);
Delay500ms(20);
LEDNum++;
P1 = ~LEDNum;
}
}
}
独立按键控制LED的移位
#include
#include
void Delay(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
// P3_0 表示的是第一个独立按键
// P1_0 表示的是第一个led灯
void main(){
unsigned char LEDNum =0;
// 独立按键代码移位的实现
P1 = ~0x01;
while(1){
if(P3_1 == 0){
Delay(20);
// 检测是否松手
while(P3_1 == 0);
Delay(20);
LEDNum++;
if(LEDNum >= 8){
LEDNum = 0;
}
P1 = ~(0x01 << LEDNum);
}
}
}
单片机LED灯使用独立按键控制led灯左右移动
#include
#include
void Delay(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
// P3_0 表示的是第一个独立按键
// P1_0 表示的是第一个led灯
void main(){
unsigned char LEDNum =0;
// 独立按键代码移位的实现
P1 = ~0x01;
while(1){
if(P3_1 == 0){
Delay(20);
// 检测是否松手
while(P3_1 == 0);
Delay(20);
LEDNum++;
if(LEDNum >= 8){
LEDNum = 0;
}
P1 = ~(0x01 << LEDNum);
}
if(P3_0 == 0){
Delay(20);
// 检测是否松手
while(P3_0 == 0);
Delay(20);
if(LEDNum == 0){
LEDNum = 7;
}else{
LEDNum--;
}
P1 = ~(0x01 << LEDNum);
}
}
}
数码管原理图
数码管的应用场景
单个数码管共阴极数码管需要给正集高电平1点亮
数码管分为共阳极和共阴极数码管
四位数码管
数码管锁存器的概念很重要74H573锁存芯片的工作原理
OE上面加一行表示的是低电平有效,如果是高电平的话不能正常的进行数据的存储和锁存
双向数据缓冲器(74HC245):作用是提高驱动能力(内部置有电源)。
OE通常表示"Output Enable",也可以称为输出使能。
LE通常表示"Latch Enable",也可以称为锁存使能。
OE(使能,接地时工作);
DIR(direction,控制A到B,或者B到A);
锁存芯片的原理图
当输出使能为低电平,锁存使能为高电平时,能让锁存器的两端连通可以正常的将输入的数据存储到晶体管中,当锁存使能为低电平时数据锁存保存的是之前输入的数据,后面无论如何修改数据都晶体管的显示也不会发生改变(也就是晶体管显示的还是上次显示的数据这个就是数据的锁存)
上拉电阻的作用:开漏状态表示的是可以输出低电平可以输出高电平
数码管的静态显示和锁存器的应用
数码管的静态显示案例一
#include
#include
sbit wei = P2^7; // 位选择器
sbit duan = P2^6; // 段选择器
unsigned char leddata[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x77, //"A"
0x7C, //"B"
0x39, //"C"
0x5E, //"D"
0x79, //"E"
0x71, //"F"
0x76, //"H"
0x38, //"L"
0x37, //"n"
0x3E, //"u"
0x73, //"P"
0x5C, //"o"
0x40, //"-"
0x00, //熄灭
0x00 //自定义
};
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
void main(){
// 打开锁存器
duan = 1;
// 段选控制数码管显示什么值
P0 = leddata[8];
// 关闭锁存器
duan = 0;
// 延迟函数
Delay(5);
// 共阴极数码管加0的时候未选通
// 打开位选择器
wei = 1;
// 数码管全部点亮
P0 = 0;
// 关闭段选择器
wei = 0;
while(1){
}
}
数码管的静态显示案例二
#include
#include "main.h"
#include
#define unit unsigned int
#define uchar unsigned char
sbit beep = P2^3;
sbit wei = P2^7; // 位选择器
sbit duan = P2^6; // 段选择器
void main(){
// 打开位锁存器
wei = 1;
P0 = 0xfe; // 高电平的16进制位0x06
//关闭位锁存器
wei = 0;
Delay(500);
// 打开段选择器
duan = 1;
P0 =0x06;
// 关闭段选择器
duan = 0;
// 延迟函数500毫秒
Delay(500);
// while循环一直循环条件为true
while(1){
}
}
练习:明白数码管的显示原理,是让数码管从0显示到9中间延时500毫秒。
#include
#include
#include "Util.h"
// 初始化数组
unsigned char leddata[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x00 //自定义
};
void main(){
// 使用for循环遍历数组
int i = 0;
// 计算数组的长度
int len = sizeof(leddata)/sizeof(leddata[0]);
for(i = 0; i< len; i++){
// 打开断选择器
duan = 1;
P0 = leddata[i];
duan = 0;
Delay(500);
// 打开位选择器
wei = 1;
P0 = 0;
wei = 0;
}
}
数码管的动态显示
数码管动态显示1-4
#include
#include
#include "Util.h"
// 初始化数组
unsigned char leddata[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x00 //自定义
};
void main(){
// 第一位数码管
wei = 1;
P0 = 0xfe;
wei = 0;
duan = 1;
P0 = leddata[1];
duan = 0;
Delay(500);
// 第二位数码管
wei = 1;
P0 = 0xfd;
wei = 0;
duan = 1;
P0 = leddata[2];
duan = 0;
Delay(500);
// 第三位数码管
wei = 1;
P0 = 0xfb;
wei = 0;
duan = 1;
P0 = leddata[3];
duan = 0;
Delay(500);
// 第四位数码管
wei = 1;
P0 = 0xf7;// 11110111
wei = 0;
duan = 1;
P0 = leddata[4];
duan = 0;
Delay(500);
}
定时器和计数器:两个功能既可以定时也可以计数,但是每次使用只能使用一个
使用定时器和计数器的使用步骤
蜂鸣器的工作原理 :通过电流的通断来实现,在电流的一通一断之间实现蜂鸣器的功能发出声音
蜂鸣器的原理图:给I/0口一个逻辑0那么E级别和B级别的时候就会导通蜂鸣器就会工作反之就不会工作
这个用一个简单的图进行描述就是
单片机的上拉电阻单片机IO空的电压是很小的无法直接驱动设备工作,单片机不是功率器件只适合做控制用不适合驱动功率器件
三极管的工作原理
蜂鸣器代码的实现(这里使用模块化编程的方式让代码更加的简洁)
void Delay(unsigned int xms) //@11.0592MHz 单片机的系统中int 表示的是16位的,在计算机中是32位或者是64位的
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
蜂鸣器函数头文件(主要运用的是模块化开发实现)
#ifndef __BEER_H_
#define __BEER_H_
void Delay(unsigned int xms);
#endif
主程序代码
#include
#include "main.h"
#include
#define unit unsigned int
#define uchar unsigned char
sbit beep = P2^3;
void main(){
int temp;
temp = 0xf0;
P1 = temp;
Delay(500);
while(1){
temp = _crol_(temp,1);
P1 = temp;
// 在低电平和高电平之间来回的切换发出声音
beep = ~beep;
Delay(500);
}
}
矩阵键盘和独立键盘的原理图
矩阵键盘使用的是并行的IO口,独立键盘使用的是单个的IO口
读取通过的电压:当按键按下的IO口会的电平会被拉低,当检测到电压为0V的时候判断键盘被按下,当我们的手松开的时候检测键盘没有按下电平回到5V。
按键的抖动问题:需要在段选的后面加延时
#include
#include "main.h"
#include
#define unit unsigned int
#define uchar unsigned char
sbit beep = P2^3;
sbit wei = P2^7; // 位选择器
sbit duan = P2^6; // 段选择器
sbit key_S2 = P3^0; // P30的IO口独立按键S2
sbit key_S3 = P3^1; // 第二个独立按键
uchar number;
//数组的定义
unsigned char code leddata[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x00 //自定义
};
// 功能函数
void diaplay(uchar i){
uchar bai,shi,ge;
// 计算个位10位和百位
bai = i / 100; // 211 /100 = 2
shi = i % 100 / 10; // 211 % 100 / 10 = 1;
ge = i % 10; // 211 % 10
}
void main(){
// 打开位锁存器
wei = 1;
P0 = 0xFE; // 高电平的16进制位0x06
//关闭位锁存器
wei = 0;
while(1){
if(key_S2 == 0){
Delay(20); // 按键抖动的消除
if(key_S2 == 0){
number++;
if(number == 10){
number = 0;
duan = 1;
P0 = leddata[number];
duan = 0;
}
// 添加松手检测
while(!key_S2){
}
}
}
// 按独立按键相减的代码
if(key_S3 == 0){
Delay(20); // 按键抖动的消除
if(key_S3 == 0){
if(number > 0){
number--;
}
while(!key_S3);
}
}
//松手之后刷新显示
duan = 1;
P0 = leddata[number];
duan = 0; // 锁存段选数据
}
}
矩阵键盘的识别
矩阵键盘与独立键盘的识别和扫描
矩阵键盘二进制取值原理图
#include
#include "main.h"
#include
#define unit unsigned int
#define uchar unsigned char
sbit wei = P2^7; // 位选择器
sbit duan = P2^6; // 段选择器
uchar number;
uchar KeyValue;
unsigned char code leddata[]={
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x77, //"A"
0x7C, //"B"
0x39, //"C"
0x5E, //"D"
0x79, //"E"
0x71, //"F"
0x76, //"H"
0x38, //"L"
0x37, //"n"
0x3E, //"u"
0x73, //"P"
0x5C, //"o"
0x40, //"-"
0x00, //熄灭
0x00 //自定义
};
// 键盘的列扫描
void ketScan(){
/*
4*4键盘的扫描
*/
P3 = 0xF0;
if(P3 != 0xF0){ // 判断键盘是否被按下
Delay(10); // 软件消除抖动
if(P3 != 0xF0){ // 列扫描
switch(P3){
case 0xE0:
KeyValue = 0; // 表示的是第一列被按下
break;
case 0xD0:
KeyValue = 1; // 表示的是第二例被按下
break;
case 0xB0:
KeyValue = 2; // 表示的是第三列被按下
break;
case 0x70:
KeyValue = 3; // 表示的是第四列被按下
break;
}
P3 = 0X0f;// 行扫描
switch(P3){
case 0x0e:
KeyValue = KeyValue; // 表示的是第一行被按下
break;
case 0x0D:
KeyValue = KeyValue + 4; // 表示的是第二行被按下
break;
case 0x0b:
KeyValue = KeyValue + 8; // 表示的是第三行被按下
break;
case 0x07:
KeyValue = KeyValue + 12; // 表示的是第四行被按下
break;
}
// 松手检测
while(P3 != 0X0f){
}
}
}
// 独立按键键盘的扫描
P3 = 0XFF;
if(P3 != 0xff){
Delay(10); // 软件消抖
switch(P3){
case 0xfe:
KeyValue = 16; // 表示的是S2被按下
break;
case 0xfD:
KeyValue = 17; // 表示的是S3被按下
break;
case 0xfb:
KeyValue = 18; // 表示的是S4被按下
break;
case 0xf7:
KeyValue = 19; // 表示的是S5被按下
break;
}
while(P3 != 0xff); // 默认会回到最后的值
}
}
void main(){
// 打开位锁存器
wei = 1;
// 高电平的16进制位0x06
P0 = 0xFE;
//关闭位锁存器
wei = 0;
while(1){
ketScan(); // 调用键盘扫描函数
duan = 1;
P0 = leddata[KeyValue]; // 显示按键的值
duan = 0;
}
}
8*8点阵屏电路图
如何赋值点亮led灯:要使用动态扫描的方式点亮led灯防止出现同时点亮的情况
8*8点阵屏原理图
#include
sbit DIO = P3^4; // 串行数据口
sbit S_CLK = P3^5; //移位寄存器时钟
sbit R_CLK = P3^6; // 输出锁存器时钟
void main(){
// ROW : 0x80 ,COL : 0xfe 通过传入和并出的方式将数据发送出去
unsigned char i,dat;
dat = 0xfe;
for(i = 0; i<8;i++){
S_CLK = 0;
R_CLK = 0;
if(dat & 0x01){
DIO = 1;
}else{
DIO = 0;
}
S_CLK = 1;
dat >>= 1;
}
dat = 0x80;
for(i = 0; i<8;i++){
S_CLK = 0;
R_CLK = 0;
if(dat & 0x01){
DIO = 1;
}else{
DIO = 0;
}
S_CLK = 1;
dat >>= 1;
}
R_CLK = 1;
while(1);
}
点阵屏实战:显示汉字-->电 字符
#include
#include
sbit DIO = P3^4; // 串行数据口
sbit S_CLK = P3^5; //移位寄存器时钟
sbit R_CLK = P3^6; // 输出锁存器时钟
/*
取模软件生成的自形码:0xef 0x01 0x6d 0x01 0x6d 0x01 0xee 0xe0 --> 电
*/
unsigned char code table[] = {
0xe0, 0xee, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0xef
};
void Send_Byte(unsigned char dat){
unsigned char i;
S_CLK = 0;
R_CLK = 0;
for(i = 0; i<8;i++){
if(dat & 0x01){
DIO = 1;
}else{
DIO = 0;
}
S_CLK = 1;
dat >>= 1;
S_CLK = 0;
}
}
void main(){
// ROW : 0x80 ,COL : 0xfe 通过传入和并出的方式将数据发送出去
unsigned char j,ROW;
while(1){
ROW = 0X80;
for(j = 0; j < 8; j++){
Send_Byte(table[j]);
Send_Byte(ROW);
R_CLK = 1;
ROW = _cror_(ROW,1); // 循环右移动
R_CLK = 0;
}
}
}
显示电子两个数字的循环显示
#include
#include
sbit DIO = P3^4; // 串行数据口
sbit S_CLK = P3^5; //移位寄存器时钟
sbit R_CLK = P3^6; // 输出锁存器时钟
/*
取模软件生成的自形码:0xef 0x01 0x6d 0x01 0x6d 0x01 0xee 0xe0 --> 电
*/
unsigned char code table[2][8] = {
0xe0, 0xee, 0x01, 0x6d, 0x01, 0x6d, 0x01, 0xef,
0xe7, 0xe7, 0xe7, 0xe7, 0x80, 0xf7, 0xfb, 0xc3
};
void Send_Byte(unsigned char dat){
unsigned char i;
S_CLK = 0;
R_CLK = 0;
for(i = 0; i<8;i++){
if(dat & 0x01){
DIO = 1;
}else{
DIO = 0;
}
S_CLK = 1;
dat >>= 1;
S_CLK = 0;
}
}
void main(){
// ROW : 0x80 ,COL : 0xfe 通过传入和并出的方式将数据发送出去
unsigned char j,k,ROW;
unsigned int z;
while(1){
for(k=0;k<2;k++){
for(z = 0; z <1000; z++){
ROW = 0X80;
for(j = 0; j < 8; j++){
Send_Byte(table[k][j]);
Send_Byte(ROW);
R_CLK = 1;
ROW = _cror_(ROW,1); // 循环右移动
R_CLK = 0;
}
}
}
}
}
IO引脚
中断系统的解释
51系列允许的5个中断源
外部中断案例
#include
#include
#define uint unsigned int
#define uchar unsigned char
sbit DU = P2^6;
sbit WE = P2^7;
sbit key_s2 = P3^0;
sbit flag = P3^7;// 外部中断信号产生脚
uchar num;
// 延时函数定义
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms){
i = 2;
j = 239;
do{
while(--j);
}while(--i);
xms--;
}
}
// 外部中断函数:外部中断1初始化
void initInterrupt(){
EA = 1; // 开启总中断
EX1 = 1; // 开外部中断1
IT1 = 1; // 开外部中断1下降沿触发
}
// 外部中断1服务函数
void initUtil() interrupt 2{
P1 = ~P1;
}
// 程序主函数
void main(){
initInterrupt(); // 外部中断1初始化
while(1){
if(key_s2 == 0){
Delay(20);
if(key_s2 == 0){
// 通过flag的操作产生下降沿
flag = 1;
flag = 0;
while(!key_s2);
}
}
}
}
计数器...
持续更新中......