一,蜂鸣器
(1)蜂鸣器的分类
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计 算机、 打印机、 复印机、 报警器、 电子玩具、 汽车电子设备、 电话机、 定 时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
1,压电式蜂鸣器
压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳 等组成。多谐振荡器由晶体管或集成电路构成,当接通电源后(1.5~15V 直流工 作电压),多谐振荡器起振,输出 1.5~5kHZ 的音频信号,阻抗匹配器推动压电 蜂鸣片发声。
2,电磁式蜂鸣器
电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电 源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜 片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
(2)无源蜂鸣器
1,工作原理
无源蜂鸣器内部没有激励源,只有给它一定频率的方波信号,才能让蜂鸣器的振动装置起振,从而实现发声,同时,输入的方波频率不同,发出的声音也不同。通过方波信号输入到振动装置中,然后通过声音输出。
2,代码实现
#include <REGX52.H>
sbit sound=P3^5;
void main()
{
EA=1;
ET1=1;
TMOD=0x10;
TH1=0xfe;//中断500微秒
TL1=0x33;
TR1=1;
while(1)
{ }
}
void Timer1_Routine() interrupt 3 // 中断函数
{
TH1=0xfe;
TL1=0x33;
sound=~sound;
}
3,仿真
4,仿真结果
二,LED数码管秒表
(1)数码管原理
一个数码管是由a、b、c、d、e、f、g、dp八个二极管组成,八个LED一端接在一起,另一端引脚引出来。二极管如果阳极连在一起,就是共阳极数码管,阴极连在一起,就是共阴极数码管。
如上图,是一个共阴极数码管,要使数码管显示不同的数字,只需点亮对应LED即可。如:数码管显示“0”,则a、b、c、d、e、f六个LED亮,g、dp这俩个LED灭,即可显示“0”。
(2)仿真图
(3)代码实现
#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; //继续启动计时器
}
三,LCD1602显示时钟
(1)LCD1602
LCD1602液晶显示屏是一种字符型液晶显示模块,可以显示数字、字母、图形以及少量自定义字符。可以显示2行16个字符,拥有16个引脚,其中8位数据总线D0-D7,和RS、RW、EN三个控制端口。
(2)LED1602指令集
常用指令:
清屏--指令码01H: 清除DDRAM和AC光标值
光标复位--指令码02H: 光标复位到地址00H位置,LCD显示DDRAM的内容不变
输入方式设置--指令码06H: 数据读写操作后,AC 自动加一,画面不动
显示开关控制--指令码0CH: 显示开,光标关,闪烁关
光标画面位移--指令码18H: 画面向左平移一个字符位,但光标不动,实现移屏
功能设置--指令码38H: 八位数据接口,两行显示,5*7点阵
(3)仿真电路原理图
(4)代码实现
#include <REGX52.H>
//LCD引脚配置
sbit LCD_RS=P3^5;
sbit LCD_RW=P3^6;
sbit LCD_EN=P3^7;
#define LCD_DataPort P2
unsigned char Hour=23,Min=59,Sec=55;
//LCD延时函数
void Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
//LCD写命令
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
Delay();
LCD_EN=0;
Delay();
}
//LCD写数据
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
Delay();
LCD_EN=0;
Delay();
}
//LCD设置光标位置
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
//LCD显示字符串
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
//LCD显示数字
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
//LCD初始化
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
//定时器初始化
void Timer0_Init()
{
TMOD=0x01;
TH0=0xFc;
TL0=0x66;
TF0=0;
TR0=1;
ET0=1;
EA=1;
}
void main()
{
LCD_Init();
Timer0_Init();
LCD_ShowString(1,1," : : ");
while(1)
{
LCD_ShowNum(1,1,Hour,2);
LCD_ShowNum(1,4,Min,2);
LCD_ShowNum(1,7,Sec,2);
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TH0=0xFc;
TL0=0x66;
T0Count++;
if(T0Count==1000)
{
Sec++;
T0Count=0;
}
if(Sec>=60)
{
Sec=0;
Min++;
}
if(Min>=60)
{
Min=0;
Hour++;
}
if(Hour>=24)
{
Hour=0;
}
}
(5)仿真结果
四,串口通信
(1)串口通信口原理及功能
数据通信就是指单片机与单片机之间或者单片机和其他设备之间的信息交换,而数据通信又分为串行通信和并行通信。
并行通信:数据的各位同时进行发送或接收的通信方式。优点是速率高。缺点是需要的传输线多,成本高,只适合近距离的数据通信。
串行通信:一位一位的按顺序的进行发送或接收的通信方式。优点是需要的传输线少,成本低。缺点是传输的速率慢,适合远距离的数据通信。
串行口的功能,就是通过串行口连接的数据传输线大大减少,可以进行远距离的数据通信。
(2)单片机与PC通信
甲、乙两单片机进行串行通信。甲机把控制8个流水灯点亮的数据发送给乙机并点亮其P1口的8个LED。方式3比方式1多了1个可编程位TB8,该位一般作奇偶校验位。乙机接收到的8位二进制数据有可能出错,需进行奇偶校验,其方法是将乙机的RB8和PSW的奇偶校验位P进行比较,如果相同,接收数据;否则拒绝接收。
甲单片机代码如下,
#include <REGX51.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 Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
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]);
Delay1ms(200);
}
}
}
乙单片机代码如下,
#include <REGX51.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;
SCON=0xd0;
PCON&=0x7f;
TH1=0xfd;
TL1=0xfd;
TR1=1;
while(1)
{
P2=Receive();
}
}
仿真电路
实验结果:
LED依次亮起
五,单片机发送,笔记本接收
(1)任务要求:
将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”,笔记本电脑用串口助手软件接收。 如果串口助手发送字符“0" 给单片机,则单片机停止发送; 如果单片机收到“1”,则继续每隔2秒发送“Hello C51”。
(2)代码
#include <REGX51.H>
#include "stdio.h"
unsigned char a;
unsigned char Flag=1;
void Delay1ms(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void UartInit(void) //9600bps@12.000MHz
{
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;
Delay1ms(2000);
}
void main()
{
UartInit();
while(1)
{
if(Flag==1)
UartSend();
}
}
//串口中断函数模板
void UART_Routine() interrupt 4 //串口中断
{
if(RI==1)
{
RI=0;
a=SBUF;
if(a=='1')Flag=1;
if(a=='0')Flag=0;
}
}