1 项目分析
- 基于点亮LED灯、LED灯闪烁,扩展到构成最简单、花样流水灯。
2 技术准备
1 流水灯硬件及原理图
-
流水灯是由多个LED灯组成的
2 C语言知识点
- 数组
-
数组声明:长度不可变
- 数据类型 数组名称[长度n] // 整数型默认为0,小数型默认为0.0,字符默认为 '\0',字符串默认为:NULL
-
声明数组并初始化
- 数据类型 数组名称[长度n] = {元素1,元素2...元素n};
- 数据类型 数组名称[] = {元素1,元素2...元素n};
-
访问:索引值从0开始
- 数组名称[索引];
-
数组长度
- sizeof(数组名称) / sizeof(数组名称[0])
-
修改数组中对应索引值位置的数据
- 数组名称[0] = 元素1;
- 数组名称[1] = 元素2;
- 数组名称[n-1] = 元素n;
-
遍历数组中的每个数据
cfor (int i = 0; i <sizeof(array) / sizeof(arr[0]); i++) { arrray[i] // 相关操作 }
c// 数组的基本使用 #include <stdio.h> int main() { // 数组的定义 int score[5]; // 数组的初始化(重点) int scores[5] = {34, 55, 67, 88, 19}; int score1[] = {34, 55, 67, 88, 19}; // 数组的索引:从0开始(重点) printf("%d ", scores[3]); // 数组的索引赋值 scores[4] = 99; printf("%d ", scores[4]); // 数组的长度 printf("\n长度:%d", sizeof(scores)); printf("\n长度:%d", sizeof(scores) / sizeof(scores[0])); // 数组的遍历(重点) int x = 0; for(; x < 5; x++) { printf(" %d ", scores[x]); } return 0; }
-
3 延时
-
介绍
-
每条指令都占一定的时间(或者机器周期)的,如果让机器什么都不做,即空指令的话,机器就会延时,然后在计算好每次延时到底有多长,外面套一个循环(或者多重循环),根据想要的延时时间即可计算出来循环的次数,延时函数基本上都是这种原理,它的参数就是用来控制循环次数的。
-
实现延时通常有两种方法:
- 硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;
- 软件延时,这种方法主要采用循环体进行。
-
-
分类
- 1)硬件延时: 使用定时器/计数器实现精确延时
- 2)软件延时: 软件延时与时间计算
- 在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。
-
方法
- 短暂延时 nop (intrins.h头文件)
- 在C51中嵌套汇编程序段实现延时
- 使用示波器确定延时时间
- 使用反汇编工具计算延时时间
- 短暂延时 nop (intrins.h头文件)
3 项目实现
方式1:常规方法
-
实验
- 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
-
代码
c/* 代码实现思路: 0 搭建代码框架 1 定义8个LED灯的端口 2 在while循环中,控制每个LED灯亮灭 3 需要设置每个LED灯亮灭的间隔(延迟函数) */ #include <reg52.h> // 宏定义 #define uint unsigned int // 1 定义8个LED灯的端口 sbit led1 = P1^0; sbit led2 = P1^1; sbit led3 = P1^2; sbit led4 = P1^3; sbit led5 = P1^4; sbit led6 = P1^5; sbit led7 = P1^6; sbit led8 = P1^7; // 函数声明 void delay(uint s); void main() { while(1) { // 2 在while循环中,控制每个LED灯亮灭 led1 = 0; // led1 亮 delay(2); led1 = 1; led2 = 0; delay(2); led2 = 1; led3 = 0; delay(2); led3 = 1; led4 = 0; delay(2); led4 = 1; led5 = 0; delay(2); led5 = 1; led6 = 0; delay(2); led6 = 1; led7 = 0; delay(2); led7 = 1; led8 = 0; delay(2); led8 = 1; } } void delay(uint s) { uint i,j,z; for(z=0;z<s;z++) { for(i=0; i<183; i++) { for(j=0; j<1000; j++); } } }
方式2:P1口赋予十六进制
-
实验
- 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
-
分析
-
代码
c/* 代码实现思路: 0 搭建代码框架 1 定义P1的端口 2 在while循环中,控制P1的取值 3 需要设置P1端口取值后间隔(延迟函数) */ #include <reg52.h> // 宏定义 #define uint unsigned int // 1 定义P1的端口 #define led P1 // 函数声明 void delays(uint s); void main2() { while(1) { // 2 在while循环中,控制P1的取值,集合延迟函数 led = 0xfe; // led1 亮 delays(1); led = 0xfd; // led2 亮 delays(1); led = 0xfb; // led3 亮 delays(1); led = 0xf7; // led4 亮 delays(1); led = 0xef; // led5 亮 delays(2); led = 0xdf; // led6 亮 delays(2); led = 0xbf; // led7 亮 delays(2); led = 0x7f; // led8 亮 delays(2); } } void delays(uint s) { uint i,j,z; for(z=0;z<s;z++) { for(i=0; i<183; i++) { for(j=0; j<1000; j++); } } }
方式3:数组存储P1电平值
-
实验
- 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
-
代码
c/* 代码实现思路: 0 搭建代码框架 1 定义P1的端口 2 定义数组,存储8个P1的值 3 在while循环中,再循环获取数组中的值,赋值给P1 4 需要设置P1端口取值后间隔(延迟函数) */ #include <reg52.h> // 宏定义 #define uint unsigned int // 1 定义P1的端口 #define led P1 // 2 定义数组,存储8个P1的值 uint led_value[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; // 3.1 定义变量,用来表示索引值 uint idx; // 函数声明 void delay(uint s); void main() { while(1) { // 3 在while循环中,再循环获取数组中的值,赋值给P1,配合延迟函数 for(idx=0; idx < 8; idx++) { led = led_value[idx]; // ledx 亮 delay(1); } } } void delay(uint s) { uint i,j,z; for(z=0;z<s;z++) { for(i=0; i<183; i++) { for(j=0; j<1000; j++); } } }
方式4: 按位左移 + 取反
-
实验
- 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
-
分析
-
代码
c/* 代码实现思路: 0 搭建代码框架 1 定义P1的端口 2 在while循环中,赋值给P1: ~(0x01 < n) 3 需要设置P1端口取值后间隔(延迟函数) */ #include <reg52.h> // 宏定义 #define uint unsigned int // 1 定义P1的端口 #define led P1 // 2.1 定义变量,用来表示左移的位数 uint n; // 函数声明 void delay(uint s); void main() { while(1) { // 2 在while循环中,赋值给P1: ~(0x01 < n),配合延迟函数 for(n=0; n < 8; n++) { led = ~(0x01 << n); // ledx 亮 delay(2); } } } void delay(uint s) { uint i,j,z; for(z=0;z<s;z++) { for(i=0; i<183; i++) { for(j=0; j<1000; j++); } } }
4 拓展:花样流水灯
花样灯1
-
实验
- 流水灯:全部亮 + 奇数灯亮 + 偶数灯亮
-
代码
c/* LED定义 单个灯:控制1~3个LED sbit ledx = P1^x; 多个灯:控制8个LED #define LED P1 全亮:P1.7 ~ P1.0 对应的端口都为低电平(0),将值写成16进制:0x00 --> 0 奇数灯亮(LED1 3 5 7-->P1.0 2 4 6)设置为低电平,写成16进制:0xaa 偶数灯亮(LED2 4 6 8-->P1.1 3 5 7)设置为低电平,写成16进制:0x55 代码的实现流程 1、定义代码的基本结构 2、定义P1端口,数组存储P1的值 3、在while循环中,遍历数组,并将值赋值给P1,同时设置对应延时 */ #include <reg52.h> #include <delay.h> #define uint unsigned int // 定义P1端口 #define LED P1 // 定义数组存储P1的值 uint values[3] = {0x00, 0xaa, 0x55}; void main1() { uint idx; while(1) { for(idx=0; idx<sizeof(values)/sizeof(values[0]); idx++) { LED = values[idx]; delay(1); } } } // file: delay.c /* 延迟函数: 功能:传入指定的值,延迟指定的秒数 参数:s 表示当前延迟的秒数 返回值:无 */ void delay(unsigned int s) { unsigned int x, i, j; for(x=0; x<s; x++) { for(i=0; i<183; i++) { for(j=0; j<1000; j++); } } } // file: delay.h #ifndef __DELAY_H // if not define 如果没有定义 #define __DELAY_H // 定义对应头文件 // 函数的声明 void delay(unsigned int s); #endif // 结束判断
c#include<reg52.h> unsigned char code table[] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x55, 0x55, 0xaa, 0xaa}; void Delay(unsigned int t); //函数声明 /*------------------------------------------------ 主函数 ------------------------------------------------*/ void main() { unsigned char i; //定义一个无符号字符型局部变量 i 取值范围 0~255 while (1) { //主循环 for (i = 0; i < 16; i++) { //程序循环执行16次,表明表格中有16个元素 P1 = table[i]; Delay(10000); } } } /*------------------------------------------------ 延时函数,含有输入参数 unsigned int t,无返回值 unsigned int 是定义无符号整形变量,其值的范围是 0~65535 ------------------------------------------------*/ void Delay(unsigned int t) { while (--t); }
c/* 定时器:T1 工作在模式1:65.536ms 1s: 50ms * 20 次数 * 机器周期 = 0.05s 次数:50000 初值:65536 - 50000 代码的实现流程 1、定义代码的基本结构 2、定义P1端口、记录定时器次数、数组存储P1的值 3、在main函数中,定义定时器 (1) 设置定时器T1的工作模式1 TMOD = 0x10; (2) 设置T1的TH1 TL1的值 TH1 = (65536 - 50000) / 256; TL1 = (65536 - 50000) % 256; (3) 打开"开关" EA = 1; // 打开总开关 TR1 = 1; // 开启定时器T1 ET1 = 1; // 开启定时器T1的外部中断 4、定义中断函数 void 中断函数名() interrupt 3 { // 4.1 重置TH1 TL1 TH1 = (65536 - 50000) / 256; TL1 = (65536 - 50000) % 256; // 4.2 定义变量,记录次数 变量++; // 4.3 判断变量是否等于20 if(变量==20) { // 流水灯逻辑 } } */ #include <reg52.h> #define uint unsigned int // 定义P1端口 #define LED P1 // 定义记录中断函数执行次数 uint times = 0; // 定义数组存储P1的值 uint p1_value[3] = {0x00, 0xaa, 0x55}; // 定义数组的索引 uint index = 0; void main2() { // (1) 设置定时器T1的工作模式1 TMOD = 0x10; // (2) 设置T1的TH1 TL1的值 TH1 = (65536 - 50000) / 256; TL1 = (65536 - 50000) % 256; // (3) 打开"开关" EA = 1; TR1 = 1; ET1 = 1; while(1) { } } // 定时器T1的中断函数 void timer1() interrupt 3 { // 4.1 重置TH1 TL1 TH1 = (65536 - 50000) / 256; TL1 = (65536 - 50000) % 256; // 4.2 定义变量,记录次数 times++; // 4.3 判断变量是否等于20 if(times==20) // 1s { // 判断index是否越界 if(index > 2) { index = 0; } // 流水灯逻辑 LED = p1_value[index]; // times重置 times = 0; // 改变index index++; } }
花样灯2
-
实验
- 每次2个灯左移 + 每次2个灯右移 + 全灭 + 全亮
-
分析
-
代码
c#include <reg52.h> #include <delay.h> #define uint unsigned int // 定义P1端口 #define Led P1 // 定义存储P1端口值的中间值的变量 uint temp; void main3() { uint x; while(1) { // 左移: Led = 0xfc; temp = 0xfc; for(x=0; x<6; x++) { delay(1); temp = temp << 1 | 0x01; Led = temp; } // 右移: Led = temp; for(x=0; x<6; x++) { delay(1); temp = temp >> 1 | 0x80; Led = temp; } // 全灭 delay(1); Led = 0xff; delay(1); // 全亮 Led = 0; delay(1); } }