一.作者小课堂
(一)蜂鸣器介绍
1.简介
蜂鸣器是一种一体化结构的电子讯响器,它采用直流电压供电,被广泛应用于各种电子产品中,如计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机和定时器等,作为发声器件。
2.分类
蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。当接通电源后,多谐振荡器起振,输出音频信号,阻抗匹配器推动压电蜂鸣片发声。压电蜂鸣片通常由锆钛酸铅或铌镁酸铅压电陶瓷材料制成,两面镀有银电极,并与黄铜片或不锈钢片粘合。
3.组成
电磁式蜂鸣器则由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。当振荡器产生的音频信号电流通过电磁线圈时,会产生磁场,使振动膜片在电磁线圈和磁铁的相互作用下周期性地振动发声。
4.工作原理
蜂鸣器的工作原理主要基于压电效应或电磁效应。其详细介绍如下:
- 压电式蜂鸣器。主要由压电陶瓷片和金属片组成,当压电陶瓷片两端施加电压时,由于逆压电效应,陶瓷片会产生机械变形,进而带动金属片振动发出声音。压电式蜂鸣器的结构简单、体积小巧、功耗低。
- 电磁式蜂鸣器。由振荡器、电磁线圈、磁铁和振动膜片等组成,当电流通过电磁线圈时,会产生磁场,振动膜片在磁铁的相互作用下周期性地振动发声。
此外,蜂鸣器还有有源蜂鸣器和无源蜂鸣器之分,有源蜂鸣器内部集成有振荡电路,可以持续发出声音,而无源蜂鸣器则需要外部振荡电路才能连续发声。
(二)数码管介绍
数码管是一种由多个发光二极管(LED)组成的显示设备,这些LED通常以七段或八段的形式排列,用于显示数字、字母、符号等信息。
1.数码管的种类包括:
①LED数码管。这是最常见的类型,由多个并联的LED组成,可以是共阳或共阴结构,即所有LED的阳极或阴极连接在一起,其他端分别连接到相应的显示数据信号。
②辉光管(Nixie tube)。这是一种较老的数码管技术,使用玻璃管和内部充填的气体来显示数字和字母,它们通常包含多个阴极,每个阴极代表一个数字或字母,通过给特定的阴极施加电压来显示相应的数字或字母。
2.数码管的应用:
数码管广泛应用于各种电子设备中,如手表、计算器、家用电器、汽车仪表盘等,它们可以显示数字、字母、符号,甚至可以播放视频和动画。随着技术的发展,数码管的设计和功能也在不断进步,例如,通过使用更高亮度的LED和使用更先进的驱动技术,可以提高数码管的显示效果和可靠性。
(三)LCD介绍
液晶显示屏(LCD,Liquid Crystal Display)是一种平面显示器技术,具有多种优点,包括低耗电量、体积小、辐射低,因此被广泛应用于电视机、计算机等电子产品中。LCD的工作原理是利用液晶分子的电光效应,在电场的作用下改变液晶分子的排列,从而影响光线的通过,显示出不同的图像。
1.LCD的结构
LCD的结构主要包括两片平行的玻璃基板,中间填充有液态晶体。这两片玻璃基板上印有电极和过滤器,用以控制光线的通过。与传统的CRT显示器相比,LCD具有更小的体积、更薄的厚度、更低的功耗和没有辐射的特点。
2.LCD的局限性
然而,LCD也有其局限性,如需要背光源来发光,在强光下可能难以看清屏幕。此外,LCD的响应速度相对较慢,这限制了其在高速动态图像显示中的应用。
为了改进这些缺点,研究人员开发出了TFT-LCD(薄膜晶体管液晶显示器),它通过改进背光技术和提高液晶分子的响应速度,显著提高了LCD的性能。
二.实践出真知
(一)驱动蜂鸣器鸣叫
1.实验要求
利用T1的中断控制P1.7引脚输出频率为1kHz方波音频信号,驱动蜂鸣器发声。系统时钟为12MHz。方波音频信号周期1ms,因此T1的定时中断时间为0.5 ms,进入中断服务程序后,对P1.7求反。
先计算T1初值,系统时钟为12MHz,则机器周期为1µs。1kHz音频信号周期为1ms,要定时计数的脉冲数为a。则T1初值:
TH1=(65 536 −a) /256;
TL1=(65 536 −a) %256
2.代码
#include<reg51.h> //包含头文件
sbit sound=P1^7; //将sound位定义为P1.7脚
#define f1(a) (65536-a)/256 //定义装入定时器高8位时间常数
#define f2(a) (65536-a)%256 //定义装入定时器低8位时间常数
unsigned int i=500;
unsigned int j=0;
void main(void)
{
EA=1; //开总中断.
ET1=1; //允许定时器T1中断 .
TMOD=0x10; //TMOD=0001 000B,使用T1的方式1定时 TH1=f1(i); //给T1高8位赋初值.
TL1=f2(i); //给T1低8位赋初值.
TR1=1; //启动T1
while(1)
{ //循环等待
i=460;
while(j<2000);
j=0;
i=360;
while(j<2000);
j=0;
}
}
void T1(void) interrupt 3 using 0 //定时器T1中断函数
{
TR1= 0; //关闭T1
sound=~sound; //P1.7输出求反
TH1=f1(i); //T1的高8位重新赋初值.
TL1=f2(i); //T1的低8位重新赋初值.
j++;
TR1=1; //启动定时器T1
}
3.实验结果
(二)LED数码管秒表的制作
1.实验要求
用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程。
2.代码
#include<reg51.h>
typedef unsigned int uint; //定义无符号整形和字符型
typedef unsigned char uchar;
uchar led[] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar led1[] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
uchar second; //秒数
uchar key; //按键次数
uint t; //用来计数,每500,代表0.1s
sbit keyif = P3^7; //按键接口
void delay(){ //延时函数,用于消除抖动
uchar i,j;
for(i=0;i<255;i++){
for(j=0;j<100;j++);
}
}
void init(void) //初始化
{
TMOD = 0x01; //0000 0010 使用方式二
second = 0; //秒数初始化为0
EA = 1; //总中断,定时器0中断允许
ET0 = 1; //允许定时器0中断
key = 0; //按键次数初始化为0
t = 0; //计数初始化为0
}
void main(){
init();
P0 = led1[second/10];
P2 = led[second%10];
while(1){
if(keyif == 0){
delay();//消除抖动
if(keyif == 0){
key++;
switch(key){
case 1: //按一次,计时器开始
TH0 = 0xee;
TL0 = 0x00;
TR0 = 1;
break;
case 2: //按两次,暂停定时器
t = 0;
TR0 = 0;
break;
case 3: //按三次,停止计时,数据清零
key = 0;
second = 0;
P0 = led1[0];
P2 = led[0];
break;
}
while(keyif == 0); //若一直按下,使其停留
}
}
}
}
void timer() interrupt 1
{
TR0 = 0; //停止计时
t++;
if(t ==20){
second++;
P0 = led1[second/10];
P2 = led[second%10];
t = 0;
}
if(second == 99){ //当计数到9.9秒,重新开始计时
second = 0;
key = 2; //相当于重新开始计时
}
TR0 = 1; //继续启动计时器
}
3.实验结果
(三)使用定时器实现一个LCD显示时钟
1.实验要求
使用定时器实现一个LCD显示时钟。采用LCD1602.最小计时单位是秒,如何获得1s的定时?可将T0定时时间定为50ms,采用中断方式进行溢出次数累计,满20次,则秒计数变量second加1;若秒计满60,则分计数变量minute加1,同时将秒计数变量second清0;若分钟计满60,则小时计数变量hour加1;若小时计数变量满24,则将小时计数变量hour清0。
2.代码
#include<reg51.h>
#include<lcd1602.h>
#define uchar unsigned char
#define uint unsigned int
uchar int_time; //定义中断次数计数变量
uchar second; //秒计数变量
uchar minute; //分钟计数变量
uchar hour; //小时计数变量
uchar code date[]=" H.I.T. CHINA "; //LCD第1行显示的内容
uchar code time[]=" TIME 23:59:55 "; //LCD第2行显示的内容
uchar second=55,minute=59,hour=23;
void clock_init()
{
uchar i,j;
for(i=0;i<16;i++)
{
write_data(date[i]);
}
write_com(0x80+0x40);
for(j=0;j<16;j++)
{
write_data(time[j]);
}
}
void clock_write( uint s, uint m, uint h)
{
write_sfm(0x47,h);
write_sfm(0x4a,m);
write_sfm(0x4d,s);
}
void main()
{
init1602(); //LCD初始化
clock_init(); //时钟初始化
TMOD=0x01; //设置定时器T0为方式1定时
EA=1; // 总中断开
ET0=1; // 允许T0中断
TH0=(65536-46483)/256; //给T0装初值
TL0=(65536-46483)%256;
TR0=1;
int_time=0; //中断次数、秒、分、时单元清0
second=55;
minute=59;
hour=23;
while(1)
{
clock_write(second ,minute, hour);
}
}
void T0_interserve(void) interrupt 1 using 1 //T0中断服务子程序
{
int_time++; //中断次数加1
if(int_time==20) //若中断次数计满20次
{
int_time=0; //中断次数变量清0
second++; //秒计数变量加 1
}
if(second==60) //若计满60s
{
second=0; //秒计数变量清0
minute ++; //分计数变量加 1
}
if(minute==60) //若计满60分
{
minute=0; //分计数变量清0
hour ++; //小时计数变量加1
}
if(hour==24)
{
hour=0; //小时计数计满24,将小时计数变量清0
}
TH0=(65536-46083)/256; //定时器T0重新赋值
TL0=(65536-46083)%256;
}
3.实验结果
(四)两单片机实现串口通信
1.实验要求
在实物实验时,如果不能找到两个普中单片机,用笔记本电脑的串口助手程序代替其中一个单片机,实现课件上描述的主要功能。甲、乙两单片机进行 方式3(或方式2)串行通信。甲机把控制8个流水灯点亮的数据发送给乙机并点亮其P1口的8个LED。方式3比方式1多了1个可编程位TB8,该位一般作奇偶校验位。乙机接收到的8位二进制数据有可能出错,需进行奇偶校验,其方法是将乙机的RB8和PSW的奇偶校验位P进行比较,如果相同,接收数据;否则拒绝接收。我们使用了一个虚拟终端来观察甲机串口发出的数据。
2.代码
甲:
//甲机发送
#include <REGX52.H>
sbit T_P=PSW^0;
unsigned char code Tab[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//流水灯程序
void Send(unsigned char dat)
{
TB8=T_P;
SBUF=dat;
while(TI==0);
TI=0;
}
void Delay(unsigned char xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void main()
{
unsigned char i;
TMOD=0x20;
SCON=0xc0;
PCON&=0x7f;
TH1=0xfd;
TL1=0xfd;
TR1=1;
while(1)
{
for(i=0;i<8;i++)
{
Send(Tab[i]);
Delay(200);//约200ms发送数据
}
}
}
乙:
//乙机接收
#include <REGX52.H>
sbit R_P=PSW^0;
unsigned char Receive()//接收一字节数据
{
unsigned char dat;
while(RI==0);//检测RI,RI=0,未接收完
RI=0; //接收数据完成RI手动清0
ACC=SBUF; //将接收缓冲器的数据存于ACC
if(RB8=R_P) //只有偶检验成功才能往下执行,接收数据
{
dat=ACC; //将ACC数据存于dat
return dat; //将接收的数据返回
}
}
void main()
{
TMOD=0x20; //设置定时器为方式2,8位自动重载
SCON=0xd0; //串口为方式3,允许接收REN=1
PCON&=0x7f; //波特率不加倍
TH1=0xfd; //波特率9600
TL1=0xfd;
TR1=1;
//REN=1;
while(1)
{
P2=Receive(); //将接收的数据送至P2口显示
}
}
3.实验结果
(五)实现“Hello C51"
1.实验要求
将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”,笔记本电脑用串口助手软件接收。 如果串口助手发送字符“0" 给单片机,则单片机停止发送; 如果单片机收到“1”,则继续每隔2秒发送“Hello C51”
2.代码
#include <REGX52.H>
#include "stdio.h"
unsigned char ch;
unsigned char Flag=1;
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void UartInit(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
EA=1;
ES=1;
}
void UartSend()
{
TI=1;
puts("Hello C51");
while(!TI);
TI=0;
Delay(2000);
}
void main()
{
UartInit();
while(1)
{
if(Flag==1)UartSend();
}
}
//串口中断函数模板
void UART_Routine() interrupt 4 //串口中断
{
if(RI==1)
{
RI=0;
ch=SBUF;
if(ch=='1')Flag=1;
if(ch=='0')Flag=0;
}
}