华 南 农 业 大 学 实 验 报 告
专业班次 组别 题目 数码管控制实验- 静态显示 姓 名 陈 建 泽 日期 2010.10.29
一、实验目的
1.学习数码管的静态控制原理
2.学习动态数码管的编程方法
二、实验设备
STC89C52单片机实验板、串口下载线、USB连接线、电脑
三、实验原理
实验的电路原理图如下所示:
LED数码管电路原理图
板上的LED数码管采用共阳型数码管,即每一位数码管都有一个公共的阳极。P2.0-P2.3分别为四位数码管的位选信号(低电平有效),P0口是数码管的段信号。 静态控制实验原理:
选中第一位LED数码管(P2.0置低),同时给P0口送不同的码字,数码管就会出现不同的数字。
成绩: 教师: 日期:
四、实验步骤
1. 分析实验所用到的电路原理图,根据需要连接跳线帽。
2. 编写程序,使用4位数码管中的其中一位循环显示0-F,间隔0.5s。
五、实验流程图
静态数码管显示流程图 六、实验程序
根据实验流程图,编写出以下实验程序。本例使用延时子程序延时,为了提高精确度,已经经过多次调试,误差在1%以内。
//**********实验二 数码管控制实验- 静态显示**************
;实验名称:数码管静态显示
;功 能:用多位数码管中的其中一位循环显示0-F
;编 写 人:陈建泽
;编写时间:20xx年10月29日
//**********************程序代码*************************
ORG 0000H ;上电或复位后初始化引导程序地址
AJMP MAIN ;转到主程序
ORG 0030H ;跳过中断服务程序入口地址区
MAIN: MOV P2,#0FEH ;选通第0位数码管
MOV R0,#00H ;R0作为字型码的记录寄存器
L1: MOV A,R0 ;A做传递参数寄存器和控制P0口
ACALL SQR ;跳到查表程序
MOV P0,A ;A控制P0,显示字型码
ACALL DEL ;延时0.5 S
INC R0 ;指向下一个字型码
CJNE R0,#16,L1 ;判断是否显示完0—F
AJMP MAIN ;显示完则从开始循环显示
//*********************查表子程序*************************
SQR: MOV DPTR,#TAB ;表首地址给DPTR
MOVC A,@A+DPTR ;查第一个字型的字型码
RET ;子程序返回
TAB: DB 0C0H,0F9H,0A4H,0B0H ;共阳极字型码表0、1、2、3
DB 99H, 92H, 82H, 0F8H ;共阳极字型码表4、5、6、7
DB 80H, 90H, 88H, 83H ;共阳极字型码表8、9、A、B
DB 0C6H,0A1H,86H, 8EH ;共阳极字型码表C、D、E、F
//*******************延时0.5S子程序***********************
DEL: MOV R3,#50 ;延时50*10=500ms=0.5S
W1:MOV R2,#50 ;与下一句一起,延时10ms,误差约0.1ms,允许范围 W2:MOV R1,#99 ;与上一句一起,延时10ms,误差约0.1ms,允许范围 W3:DJNZ R1,W3 ;自减,共198MC
DJNZ R2,W2 ;重新装入50
DJNZ R3,W1 ;自减
RET ;子程序返回
END ;程序结束
//*********************程序编写结束***********************
七、调试遇到问题及解决办法
(二)不清楚汇编里面的表是放在哪里?
分析:表式放在程序存储器中,不是RAM中。所以查询表时必须使用MOVC指令,不能使用MOV,否则将会出现很多错误。讲过调试和查看,本程序的表从程序存储器的0X0047H的位置开始存储表。
(三)其他注意事项
1.程序的最后必须加上END,否则将导致程序无法执行。
2.必须理解清楚转移指令的含义,例如CJNE,是在不相等的时候转移,不是相等的时候转移。为了这个,在但不调试调试时花了很长时间才发现,下次应该不会出错了。
第二篇:实验四:数码管静态显示
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815
实验四:数码管静态显示
一、 实验目的
1、 掌握数码管的原理;
2、 熟悉74HC595的串并扩展芯片的使用;
3、 掌握芯片接口的编程技巧;
4、 掌握数据定义在flash区的方法;
二、 实验原理
1、 认识开发板上的数码管
板上的数码管为共阴四位,每个位选端均采用8050扩流,4个8050分别用单片机的PC0~PC3控制,高电平选通;8个段选分别通过1k电阻与74HC595的8个输出端口连接。该款数码管适合于动态扫描显示。
2、74HC595为串并转换芯片,详细参数见74HC595.pdf,内部框图和与单片机的连接关系如下图:
Editor:*轩辕十四* Created date:2010-2-2 - 1 -
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815
下图为74HC595的工作时序图:
Editor:*轩辕十四* Created date:2010-2-2 - 2 -
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815
工作时,把数据送入SER端,CLK即SCK端送入时钟脉冲,时钟上升沿后移入数据后,RCK送入一个高电平脉冲,上升沿时数据送到输出端,因此具有锁存功能。
OE端为输出使能,OE高电平时输出端为高阻状态,无法输入和输出,正常显示时应令OE端为低电平,OE端一般用于产生秒级的闪烁效果。
3、接口定义的方法
前几个例子中,操作单片机的IO口均简单地对寄存器赋值或直接访问,这种方法虽然简单容易上手,但是可移植性差,不适合团队合作编程。更好的方法是让软件本来对硬件的依赖很少,涉及硬件的操作尽可能甚至全部用宏定义的形式进行操作,这样移植程序的时候工作量就很少。如下,SCK与PC7连在一起,我们用宏定义实现对其的操作。
#define SCK PC7
#define IO_DDR DDRC
#define IO_PORT PORTC
#define SCK_H IO_PORT|=1<<SCK
#define SCK_L IO_PORT&=~(1<<SCK)
SCK_H执行时,PC7便输出高电平,SCK_L执行时,PC7变为低电平。更重要的是,这些语句在执行的时候不会影响到其他IO的电平。
从程序上看,这样做会使程序头比较大,而且这些语句执行时间也比直接操作寄存器来得长。但是,这样做,程序编译出来的文件并不会显著变大,而且执行时间大多数情况下也足够小没有影响,特别对于AVR单片机,所以进行接口定义的时候强烈建议用这种方法。
4、数据定义在flash区的方法
显示数字时,比如显示数字8,数码管的8个段选均要高电平,595中需要移入7个高Editor:*轩辕十四* Created date:2010-2-2
- 3 -
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815
电平,我们用11111110来表示,记为0xfe,称之为数字“8”的字模,保留最后一位,最后一位是小数点位,当要显示小数点时,令其为“1”即可。同理,只要知道数码管其它段与74HC595的连接关系,很容易得到其他数字的字模,这里直接给出,0~9对应的字模为:
0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6
这些数据要放在储存区,放置于SRAM(内存)和flash(硬盘)中均可,由于flash容量远比SRAM大,这里放置于flash中。如果放置于内存中,比较简单,代码如下,直接进行全局定义:
Unsigned char table[]={0xfc,0x60,0xda,0xf2,0x66,
0xb6,0xbe,0xe0,0xfe,0xf6};
放置于flash中,需要头尾夹“#pragma data”,并且需要加const表示静态变量。#pragma data:code
const unsigned char table[]={0xfc,0x60,0xda,0xf2,0x66,
0xb6,0xbe,0xe0,0xfe,0xf6,};
#pragma data:data
三、 硬件连接
连接PC0~PC7。
四、 实验代码
// 必须包含这2个必要的头文件
#include<iom16v.h>
#include<macros.h>
// 定义接口
#define SCK PC7
#define RCK PC6
#define OE PC5
#define SER PC4
#define SMG3 PC3
#define SMG2 PC2
#define SMG1 PC1
#define SMG0 PC0
#define IO_DDR DDRC
#define IO_PORT PORTC
// 定义接口的高、低电平
#define SCK_H IO_PORT|=1<<SCK
#define SCK_L IO_PORT&=~(1<<SCK)
#define RCK_H IO_PORT|=1<<RCK
#define RCK_L IO_PORT&=~(1<<RCK)
#define OE_H IO_PORT|=1<<OE
#define OE_L IO_PORT&=~(1<<OE)
#define SER_H IO_PORT|=1<<SER
#define SER_L IO_PORT&=~(1<<SER)
#define SMG3_H IO_PORT|=1<<SMG3
#define SMG3_L IO_PORT&=~(1<<SMG3)
#define SMG2_H IO_PORT|=1<<SMG2
#define SMG2_L IO_PORT&=~(1<<SMG2)
Editor:*轩辕十四* Created date:2010-2-2 - 4 -
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815
#define SMG1_H IO_PORT|=1<<SMG1
#define SMG1_L IO_PORT&=~(1<<SMG1)
#define SMG0_H IO_PORT|=1<<SMG0
#define SMG0_L IO_PORT&=~(1<<SMG0)
//**将两个pragma中间的数据放到程序寄存器中 即放到flash中**//
//** 以免占用内存 即sram的空间 **//
#pragma data:code
const unsigned char table[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6, // 数字字模 0x01};// 小数点位
#pragma data:data
//************************************************************************//
void delay_ms(unsigned int t) // 毫秒级延时函数
{
while(t--)
{
delay_us(1000); // 执行时间大约1ms
}
}
void delay_us(unsigned int t) // 微秒级延时函数
{
while(t--)
{ // 执行一周大约1us
asm("nop"); // 嵌入汇编,表示"空操作",
asm("nop"); // 不执行任何指令,消耗时间,
asm("nop"); // 起到延时的作用
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
}
// 系统初始化
void System_Init()
{
IO_DDR=0xff;
}
// 显示函数
void show(unsigned char num)
{
unsigned char temp;
num=table[num]; // num对应table中的字模,字模决定显示字形
for(temp=0;temp<8;temp++) // 共移入8位数据,恰好驱动数码管
{
if(num&(1<<temp)) // num对应字模,temp对应第temp位
{
SER_H; // 根据字模的1置位数据端
}
else
{
SER_L; // 字模的0置零数据端
}
Editor:*轩辕十四* Created date:2010-2-2 - 5 -
华南理工大学无线电爱好者协会 AVR-R&D V2.1 QQ群:63191815 SCK_H;
SCK_L; // 高电平脉冲,上升沿数据移入
}
RCK_H;
RCK_L; // 高电平脉冲,数据输出
OE_L; // 使能输出端口
SMG0_H;
SMG1_H; // 4位数码管均使能显示
SMG2_H;
SMG3_H;
}
// 主函数
void main()
{
unsigned char i=0;
System_Init();
while(1)
{
show(i++); // 显示 i
delay_ms(1000);
if(i==10)i=0;
}
}
五、 演示效果
正确连接,程序下载后,四位数码管全部点亮,并依次显示0000,1111,……,9999,0000,以此不断循环。
思考和提高:
1、 如何任意位置任意时间把小数点显示出来?
2、 如果实现不同位显示不同数字?
Editor:*轩辕十四* Created date:2010-2-2 - 6 -