007-变量的作用域和LED点阵
变量
一、局部变量和全局变量
- 局部变量:函数内申明的变量,只在函数内有效。
- 全局变量:函数外部申明的变量。一个源程序文件有一个或者多个函数,全局变量对他们都起作用。
备注:全局变量有副作用,降低了函数的独立性,降低函数的通用性,能用局部变量不用全局变量。
二、变量的存储类型
- 自动变量:局部变量不加static修饰即属于自动变量,也叫动态变量。
- 静态变量:所有的全局变量都是静态变量,局部变量加了static关键字也属于静态变量。
例如:
void main()
{
unsigned char i; //自动变量
static unsigned char j; //静止变量
}
点阵LED
由于普中A2开发板的8×8点阵LED由74HC595控制DPa~DPh,所以先介绍74HC595芯片。
74HC595是一个8位串行输入、并行输出的位移缓存器,其中并行输出为三态输出(即高电平、低电平和高抗)。
74HC595 是具有 8 位移位寄存器和一个存储器,三态输出功能。移位寄存器和存储器是分别的时钟。数据SCK的上升沿输入,在 RCK 的上升沿进入到存储器中。如果两个时钟连在一起,则移位寄存器总是比存储器早一个脉冲。移位寄存器有一个串行输入(DS),和一个串行输出(Q7 非),和一个异步的低电平复位, 存储寄存器有一个并行 8 位的, 具有三态的总线输出, 当 MR 为高电平,OE 为低电平时,数据在 SHCP 上升沿进入移位寄存器,在 STCP 上升沿输出到并行端口。
74HC595管脚图
备注:疑似管脚名称有误,为了方便学习普中A2板子,所以依据提供的图来看
15和1至7脚:QA~QH——并行数据输出,简记为并出;
9脚:QH'——串行数据输出,简记为串出;
10脚:SRCLR非( MR)——低电平复位引脚
11脚:SRCLK(SHCP)——移位寄存器时钟输入,简记为输入开关;
12脚:RCLK(STCP)——存储寄存器时钟输入,简记为输出开关;
13脚:OE非——输出有效
14脚:SER(DS)——串行数据输入,简记为串入,输入的八位数字由此进入;工作过程(个人理解):
- 初始化:SRCLK为0,RCLK为1;此时SER口有八位数字,从高位到低位依次为“76543210”;
- 写入:第7位数字写入SER;
- SRCLK由0->1(上升沿到达),SER中的第7位数字通过移位寄存器到达QH;
- SRCLK由1->0(下降沿到达),第6位数字写入SER;
- SRCLK由0->1(上升沿到达),SER中的第6位数字通过移位寄存器到达QG;
- 循环移动八位数字由高位至低位到达QH至QA,但数据还没有被输出;
- RCLK由0->1,QH至QA中的全部数据一次性被输出;
- 正确的74HC595管脚图应该为下图:
实验一:实现点亮8×8点阵LED左上角第一个灯
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存
#include "intrins.h"
//功能:点亮8×8点阵LED左上角的小灯
//目标:P0^7 = 0;DPh = 1,其他为0
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
//定义使用的IO口
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
sbit LED=P0^7;
/*
* 函 数 名 : Hc595SendByte(u8 dat)
* 函数功能 : 通过 595 发送 1 个字节的数据
* 输 入 : dat: 1 个 595 输出数值
* 输 出 : 无
*/
void Hc595SendByte(u8 dat)
{
u8 a;
SRCLK = 1;
RCLK = 1;
for(a=0;a<8;a++) //发送 8 位数
{
SER = dat >> 7; //从最高位开始发送
dat <<= 1;
SRCLK = 0; //发送时序
_nop_();
_nop_();
SRCLK = 1;
}
RCLK = 0;
_nop_();
_nop_();
RCLK = 1;
}
/*
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*/
void main()
{
LED=0; //使第一列为低电平。
while(1)
{
Hc595SendByte(0x80); //1000 0000
}
}
备注及说明:
- 所实现的结果有Bug,表现为DPh控制的小灯错误规律闪烁,问题暂未解决。
实验二:实现8×8点阵LED第一列的流水动态显示
#include<reg52.h> //头文件
#include<intrins.h> //头文件
sbit SRCLK = P3^6; //74HC595使用的IO定义
sbit LCLK = P3^5; //LCLK即为RCLK,如果使用#include<reg51,h>,则无需更改
sbit SER = P3^4;
//74HC595发送函数
void Hc595SendByte(char date) //定义74HC595的发送函数
{
unsigned char a;
SRCLK = 1;
LCLK = 1;
for(a=0;a<8;a++) //发送8位数
{
SER = date >> 7; //从最高位开始发送
date <<= 1;
SRCLK = 0; //发送时序
_nop_();
_nop_();
SRCLK = 1;
}
LCLK = 0;
_nop_();
_nop_();
LCLK = 1;
}
//延时函数
void delay(int i)
{
while(i--);
}
//主函数
void main()
{
unsigned char ledNum;
unsigned char direction = 0; //0左移
P0 = 0x7F; //保证第一列为低电平
ledNum = 0xEF; //1111 1110
while(1)
{
Hc595SendByte(ledNum); //1111 1110
delay(50000);
ledNum = _crol_(ledNum, 1); //_corl_为循环左移
}
}
备注及说明:
#include<51.h>
和#include<reg52.h>
的区别是:获取变量地址不同、寄存器地址不同、扩展不同。
1.获取变量地址不同
(1)reg51:reg51声明变量后,不能用取地址运算符&获取其地址,编译无法通过,编译器会提示非法操作。
(2)reg52:reg52声明变量后,能用取地址运算符&获取其地址,编译能通过,编译器不会提示非法操作。
2.寄存器地址不同
(1)reg51:reg51有任何一种型号的51单片机都有的基本SFR寄存器的地址,没有T2和DPTR1寄存器的地址。
(2)reg52:reg52是对REG51进行扩充,增加了T2和DPTR1寄存器的地址。#include<intrins.h>
应用于程序设计,一般出C51单片机编程中,一般程序中需要使用到空指令_nop_();字符循环移位指令_crol_等时使用。- 这里用到了_crol_这个外部函数,表达的意思是:循环左移。这个函数是包含在"intrins.h"中。
- 关于_corl_(cror)和<<(>>)的区别:
注意循环左移和LED = LED<<1;的区别:
如果这里LED = 0xfe;也就是0x1111 1110;
则LED = LED << 1;
后LED的结果为0x1111 1100,最右一位填入了0。
LED = _crol_(LED,1);
面的有两个参数,LED是将要左移的数据,1表示将要左移的位数,如果为2就是左移2位。
LED = _crol_ (LED,1);
后LED的结果为0x1111 1101,最右一位是左移消逝的第7位。
实验三:利用中断函数实现点阵LED的全亮效果
#include<reg52.h> //头文件
#include<intrins.h>
//功能:利用中断函数实现点阵LED的全亮效果
//定义使用的IO口
sbit SER = P3^4;
sbit LCLK = P3^5;
sbit SRCLK = P3^6;
//定义8×8点阵LED的列选通信号,一次亮一列
unsigned char dian_zhen_LED[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
//申明74HC595发送函数
void HC595Send(char date);
//主函数
void main()
{
TMOD = 0x01; //设置定时器,晶振频率12Mhz,计次间隔1ms
TH0 = 0xFC;
TL0 = 0x18;
TR0 =1;
EA = 1; //打开中断总开关
ET0 = 1; //打开T0中断开关
while(1); //保持持续刷新
}
//定义74HC595发送函数
void HC595Send(char date)
{
unsigned char a;
SRCLK = 1; //74HC595初始状态定义
LCLK = 1; //74HC595初始状态定义
for(a=0; a<8; a++) //从高位到低位依次发送8位数字
{
SER = date >> 7;
date <<= 1;
//SRCLK由0->1(上升沿到达),一位数字通过移位寄存器到达QH至QA中某一位,但数据还没有被输出
SRCLK = 0;
_nop_();
_nop_();
SRCLK = 1;
}
LCLK = 0; //RCLK由0->1,QH至QA中的全部数据一次性被输出
_nop_();
_nop_();
LCLK = 1;
}
//中断函数
void InterruptTime0() interrupt 1 //中断类型为T0中断,1为中断编号
{
static unsigned char i = 0; //此处要加static定义为静态变量,否则每次只执行“case 0”语句
TH0 = 0xFC; //设置定时器,晶振频率12Mhz,计次间隔1ms
TL0 = 0x18; //注意:右移TF0溢出时,进入定时器中断硬件自动清零,不在需要软件清零,省略语句TF0=0;
P0 = 0xFF; //消除鬼影
HC595Send(0xFF); //使DPh至DPa保持高电平
switch(i) //
{
case 0: P0 = dian_zhen_LED[i];i++;break;
case 1: P0 = dian_zhen_LED[i];i++;break;
case 2: P0 = dian_zhen_LED[i];i++;break;
case 3: P0 = dian_zhen_LED[i];i++;break;
case 4: P0 = dian_zhen_LED[i];i++;break;
case 5: P0 = dian_zhen_LED[i];i++;break;
case 6: P0 = dian_zhen_LED[i];i++;break;
case 7: P0 = dian_zhen_LED[i];i=0;break;
default:break;
}
}
实验四:实现8×8点阵LED显示“爱心”图案
#include<reg52.h> //头文件
#include<intrins.h>
//定义使用的IO口
sbit SER = P3^4;
sbit LCLK = P3^5;
sbit SRCLK = P3^6;
//定义图案“爱心”取模参数
unsigned char ai_xin[8] = {0x30,0x78,0x7C,0x3E,0x3E,0x7C,0x78,0x30,};
//定义8×8点阵LED的列选通信号,一次亮一列
unsigned char dian_zhen_LED[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
//申明74HC595发送函数
void HC595Send(char date);
//申明延时函数
void delay(int i);
//主函数
void main()
{
unsigned char i;
while(1)
{
for(i=0; i<8; i++) //图案动态刷新
{
P0 = dian_zhen_LED[i]; //点阵LED从左至右依次列低电平
HC595Send(ai_xin[i]); //第一列图案显示
delay(100); //延时
HC595Send(0x00); //消除鬼影,普中A2好像不需要消除
}
}
}
//定义74HC595发送函数
void HC595Send(char date)
{
unsigned char a;
SRCLK = 1; //74HC595初始状态定义
LCLK = 1; //74HC595初始状态定义
for(a=0; a<8; a++) //从高位到低位依次发送8位数字
{
SER = date >> 7;
date <<= 1;
//SRCLK由0->1(上升沿到达),一位数字通过移位寄存器到达QH至QA中某一位,但数据还没有被输出
SRCLK = 0;
_nop_();
_nop_();
SRCLK = 1;
}
LCLK = 0; //RCLK由0->1,QH至QA中的全部数据一次性被输出
_nop_();
_nop_();
LCLK = 1;
}
//定义延时函数
void delay(int i)
{
while(i--);
}
实验五:显示图案“我爱你”
#include<reg52.h> //头文件
#include<intrins.h>
//定义使用的IO口
sbit SER = P3^4;
sbit LCLK = P3^5;
sbit SRCLK = P3^6;
//申明74HC595发送函数
void hc595Send(char date);
//定义图案“我爱你”取模参数
unsigned char wo_ai_ni[40] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x66,0x66,0x7E,0x7E,0x66,0x66,0x00,
0x30,0x78,0x7C,0x3E,0x3E,0x7C,0x78,0x30,
0x00,0x7C,0x7E,0x06,0x06,0x7E,0x7C,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
//定义8×8点阵LED的列选通信号,一次亮一列
unsigned char dian_zhen_LED[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
//主函数
void main()
{
TMOD = 0;
TH0 = 0xFC;
TL0 = 0x18;
TR0 = 1;
EA = 1;
ET0 = 1;
while(1);
}
//定义74HC595发送函数
void hc595Send(char date)
{
unsigned char a = 0;
SRCLK = 1;
LCLK = 1;
for(a=0; a<8; a++)
{
SER = date >> 7;
date <<= 1;
SRCLK = 0;
_nop_();
_nop_();
SRCLK = 1;
}
LCLK = 0;
_nop_();
_nop_();
LCLK = 1;
}
//中断函数
InterruptTime0() interrupt 1
{
static unsigned int cnt = 0;
static unsigned char index = 0;
static unsigned char i = 0;
TH0 = 0xFC;
TL0 = 0x18;
hc595Send(0x00); //消除鬼影
switch(i)
//动态刷新:整个40×8的图片切割成32张图,从index位置开始依次刷新一遍
{
case 0: hc595Send(wo_ai_ni[index + 0]); P0 = dian_zhen_LED[0]; i++; break; //显示第index张图片第一列
case 1: hc595Send(wo_ai_ni[index + 1]); P0 = dian_zhen_LED[1]; i++; break;
case 2: hc595Send(wo_ai_ni[index + 2]); P0 = dian_zhen_LED[2]; i++; break;
case 3: hc595Send(wo_ai_ni[index + 3]); P0 = dian_zhen_LED[3]; i++; break;
case 4: hc595Send(wo_ai_ni[index + 4]); P0 = dian_zhen_LED[4]; i++; break;
case 5: hc595Send(wo_ai_ni[index + 5]); P0 = dian_zhen_LED[5]; i++; break;
case 6: hc595Send(wo_ai_ni[index + 6]); P0 = dian_zhen_LED[6]; i++; break;
case 7: hc595Send(wo_ai_ni[index + 7]); P0 = dian_zhen_LED[7]; i=0; break;
default:break;
}
cnt++; //计次加1,一次时间间隔为1ms
if(cnt == 100) //时间到达0.1秒
{
cnt = 0; //计次清零
index++; //下一张图片
if(index == 32) //刷新至第32张图
{
index = 0; //从头开始
}
}
}
备注及说明:
- 普中开发攻略有误,正确的取模软件参数为下图所示:
007-变量的作用域和LED点阵的更多相关文章
- js学习之变量、作用域和内存问题
js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...
- 深入理解 JavaScript 变量的作用域和作用域链
一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...
- js变量及其作用域(附例子及讲解)
Javascript和Java.C这些语言不同,它是一种无类型.弱检测的语言.它对变量的定义并不需要声明变量类型,我们只要通过赋值的形式,可以将各种类型的数据赋值给同一个变量 工具/原料 Ch ...
- 单片机与控制实验(2)——LED点阵显示屏
一.实验目的和要求 了解LED点阵显示的基本原理和实现方法.掌握点阵汉字库的编码和从标准字库中提取汉字编码的方法. 二.实验设备 单片机测控实验系统 LED点阵显示器实验模块 Keil开发环境 STC ...
- 基于Proteus仿真的Arduino学习(2)——LED点阵探究A(LED点阵基础)
一.前言: 随着LED的普及,以LED点阵为基础的显示设置层出不穷.例如,公交车的线路提示牌.高速公路的信息提示牌,安装在大楼上的广告屏幕等.下面,我们将由简单到复杂地探索各种LED点阵的使用方法,同 ...
- javascript变量的作用域
javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象 讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...
- Js中变量的作用域
一.理解函数作用域需要理解以下几点: 1.函数变量的作用域有全局变量和局部变量两种,全局变量写在函数的最前面,局部变量写在函数体内,局部变量省略了var 也就默认成为了全局变量! 2.函数 ...
- 《征服 C 指针》摘录2:C变量的 作用域 和 生命周期(存储期)
在开发一些小程序的时候,也许我们并不在意作用域的必要性.可是,当你书写几万行,甚至几十万行的代码的时候,没有作用域肯定是不能忍受的. C 语言有如下 3 种作用域. 1.全局变量 在函数之外声明的变量 ...
- JavaScript变量和作用域
认识JavaScript中的变量 JavaScript中的变量有两种类型,一种是基本类型.一种是引用类型. 基本数据类型:Defined,Null,Boolean,Number,String.注意St ...
随机推荐
- Alternating Strings Gym - 100712D 简单dp && Alternating Strings II Gym - 100712L 数据结构优化dp
比赛链接:https://vjudge.net/contest/405905#problem/D 题意: 给你一个长度为n的由0或1构成的串s,你需要切割这个串,要求切割之后的每一个子串长度要小于等于 ...
- 【2020杭电多校】Total Eclipse 并查集+思维
题目链接:Total Eclipse 题意: t组输入,给你一个由n个点,m条边构成的图,每一个点的权值是ai.你每一次可以选择一批联通的点,然后让他们的权值都减去1.问最后把所有点的权值都变成0需要 ...
- C++ part3
函数和const references: C++中const用于函数重载 有些情况可以重载,有些不行,具体看↑. 隐式类型转换 references: nowcoder 对于内置类型,低精度的变量给高 ...
- BZOJ1001 狼抓兔子(网络流转最短路:对偶图)
题意: 给一个如图形式的\(n*m\)的方格,从左上走到右下,给出边权,问分成两块所需的最小代价.\(n,m\leq1000\). 思路: 显然是个最小割,但是\(O(n^2m)\)的复杂度很高,虽然 ...
- 2019牛客多校第五场C generator 2(BSGS)题解
题意: 传送门 已知递推公式\(x_i = a*x_{i - 1} + b\mod p\),\(p\)是素数,已知\(x_0,a,b,p\),给出一个\(n\)和\(v\),问你满足\(x_i = v ...
- mssql数据库提权(xp_cmdshell)
1.关于 "xp_cmdshell" "存储过程":其实质就是一个"集合",那么是什么样的结合呢,就是存储在SqlServer中预先定义好的 ...
- Github Docs All In One
Github Docs All In One docs https://docs.github.com/en https://github.com/github/docs GitHub REST AP ...
- WebAssembly All In One
WebAssembly All In One wasm https://webassembly.org/ https://developer.mozilla.org/en-US/docs/WebAss ...
- Beacon API
Beacon API User Tracking https://caniuse.com/#feat=beacon Question & Solution Beacon API 不会延缓网页卸 ...
- 如何实现一个 markdown 图片粘贴上传的博客后台系统
如何实现一个 markdown 图片粘贴上传的博客后台系统 js 实现 drag & drop / copy & paste image uploader MongoDB 设计文档对象 ...