数字信号与模拟信号
模拟信号:连续的
数字信号:离散的,只有0和1两种状态
用灯做例子,如果一个开关只能控制灯的亮和灭,就是传递数字信号,如果这个开关能控制亮的多少,比如30%,66%这种,就是传递模拟信号
AD与DA
1、基本知识讲解
2、运算放大器
3、AD模数转换
LCD1602显示屏显示电位器、热敏电阻、光敏电阻的阻值
xpt2046.c
#include<regx52.h>
sbit XPT_CS=P3^5;
sbit XPT_DCLK=P3^6;
sbit XPT_DIN=P3^4;
sbit XPT_DOUT=P3^7;
unsigned int read_AD(unsigned char command)
{
unsigned int value=0;
unsigned char i;
XPT_DCLK=0;
XPT_CS=0;
for(i=0;i<8;i++)
{
XPT_DIN=command&(0x80>>i); //写字命令
XPT_DCLK=1;
XPT_DCLK=0;
}
for(i=0;i<16;i++)
{
XPT_DCLK=1;
XPT_DCLK=0;
if( XPT_DOUT)
{
value=value|(0x8000>>i); //读16位数据,注意存放顺序从高位到低位
}
}
XPT_CS=1;
if(command&0x08) //8位分辨率,则右移8位,因为从高位开始读,也就是实际8位数存放在高8位,右移8位才是实际数值
{return value>>8;}
else
{return value>>4;} //12位分辨率,所以右移4位就行
}
xpt2046.h
#ifndef __XPT2046_H__
#define __XPT2046_H__
//8位分辨率
#define XP_8 0x9c //电位器正
#define VBAT_8 0xAC //GR正 光敏电阻
#define YN_8 0xCC
#define YP_8 0xDC //NTC正 热敏电阻
#define AUX_8 0xEC
//12位分辨率
#define XP_12 0x94
#define VBAT_12 0xA4
#define YN_12 0xC4
#define YP_12 0xD4
#define AUX_12 0xE4
unsigned int read_AD(unsigned char command);
#endif
main.c
#include<regx52.h>
#include"Delay.h"
#include"xpt2046.h"
#include"lcd1602.h"
unsigned int value;
void main ()
{
LCD_Init();
LCD_ShowString(1,1,"ADJ RG NTC");
while(1)
{
value=read_AD(XP_12);
LCD_ShowNum(2,1,value,4);
Delay(100);
value=read_AD(VBAT_12);
LCD_ShowNum(2,7,value,4);
Delay(100);
value=read_AD(YP_12);
LCD_ShowNum(2,13,value,4);
Delay(100);
}
}
4、DA数模转换
通过定时器结合DA实现呼吸灯的效果
main.c
#include<regx52.h>
#include"delay.h"
#include"Timer0.h"
sbit DA=P2^1;
unsigned char counter,compare;
unsigned char i;
void main ()
{
Timer0_Init();
while(1)
{
for(i=0;i<100;i++)
{
compare=i;
Delay(10);
}
for(i=100;i>0;i--)
{
compare=i;
Delay(10);
}
}
}
void Timer0_Routine() interrupt 1
{
TL0 = 0x9C;
TH0 = 0xFF;
counter++;
counter%=100;
if(counter<compare)
{
DA=1;
}
else
{
DA=0;
}
}
红外遥控(外部中断)
1、基本知识讲解
2、红外遥控
按下遥控器在LCD1602显示屏上显示地址码和命令码,长按实现累加、累减
main.c
#include<regx52.h>
#include"delay.h"
#include"LCD1602.h"
#include"IR.h"
unsigned char Address,Command,num;
void main ()
{
LCD_Init();
IR_init();
LCD_ShowString(1,1,"ADDR CMD NUM");
LCD_ShowString(2,1,"00 00 000");
while(1)
{
if(IR_GetDataFlag()||IR_GetRepeatFlag())
{
Address=IR_GetAddressFlag();
Command=IR_GetCommandFlag();
LCD_ShowHexNum(2,1,Address,2);
LCD_ShowHexNum(2,7,Command,2);
if(Command==IR_VOL_ADD){num++;}
if(Command==IR_VOL_MINUS){num--;}
LCD_ShowNum(2,14,num,3);
}
}
}
IR.C
#include"Int0.h"
#include"Timer0.h"
#include<regx52.h>
unsigned int IR_Time; //存储定时器计时的时间
unsigned char IR_state; //红外状态位,0表示空闲状态,为高电平,1表示工作状态,为低电平
unsigned char IR_Data[4]; //用数组存储32位数据
unsigned char IR_pData; //用指针数组表示32位数据
unsigned char IR_DataFlag;//收到数据标志位
unsigned char IR_RepeatFlag; //重复标志位
unsigned char IR_Address; //地址码
unsigned char IR_Command; //命令码
void IR_init() //红外遥控初始化
{
int0_init();
Timer0_Init();
}
unsigned char IR_GetDataFlag() //红外遥控获取收到数据帧标志位,1为收到,0为没收到
{
if(IR_DataFlag)
{IR_DataFlag=0;return 1;}
else
{return 0;}
}
unsigned char IR_GetRepeatFlag() // 红外遥控获取收到连发帧标志位,是否收到连发帧,1为收到,0为未收到
{
if(IR_RepeatFlag)
{IR_RepeatFlag=0;return 1;}
else
{return 0;}
}
unsigned char IR_GetCommandFlag()//红外遥控获取收到的命令数据
{return(IR_Command);}
unsigned char IR_GetAddressFlag() //红外遥控获取收到的地址数据
{return(IR_Address);}
void Int0_Routine() interrupt 0 //外部中断0,下降沿触发
{
if(IR_state==0) //这里把高电平空闲状态写为0,1是低电平
{
Timer0_setcounter(0); //定时器清0
Timer0_run(1); //开始计时
IR_state=1; //置状态为1
}
else if(IR_state==1)//状态1,等待Start信号或Repeat信号
{
IR_Time=Timer0_Getcounter(); //获取上一次中断到此次中断的时间
Timer0_setcounter(0); //定时计数器清0
if(IR_Time>13500-500&&IR_Time<13500+500) //如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
{
IR_state=2; //置状态为2
}
else if(IR_Time>11250-500&&IR_Time<11250+500) //如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
{
IR_RepeatFlag=1; //置收到连发帧标志位为1
Timer0_run(0);//定时器停止
IR_state=0; //置状态为0
}
else //接收出错
{
IR_state=1;
}
}
else if(IR_state==2) //状态2,接收数据
{
IR_Time=Timer0_Getcounter(); //获取上一次中断到此次中断的时间
Timer0_setcounter(0);//定时计数器清0
if(IR_Time>1120-500&&IR_Time<1120+500)//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
{
IR_Data[IR_pData/8]&=~(0x01<<IR_pData%8); //数据对应位清0
IR_pData++; //数据位置指针自增
}
else if(IR_Time>2250-500&&IR_Time<2250+500) //如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
{
IR_Data[IR_pData/8]|=(0x01<<IR_pData%8);//数据对应位置1
IR_pData++;//数据位置指针自增
}
else //接收出错
{
IR_pData=0; //数据位置指针清0
IR_state=1; //置状态为1
}
if(IR_pData>31) //如果接收到了32位数据
{
IR_pData=0; //数据位置指针清0
if((IR_Data[0]==~IR_Data[1])&& (IR_Data[2]==~IR_Data[3])) //数据验证
{
IR_Address=IR_Data[0];//转存数据
IR_Command=IR_Data[2];
IR_DataFlag=1; //置收到数据标志位为1
}
Timer0_run(0); //定时器停止
IR_state=0; //置状态为0
}
}
}
Timer0.c
#include<regx52.h>
void Timer0_Init() //1毫秒@12.000MHz 软件生成的代码
{
//AUXR &= 0x7F; //定时器时钟12T模式,旧版本单片机是12MHZ,不需要再设置为12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0; //设置定时初始值
TH0 = 0; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
}
void Timer0_setcounter(unsigned int value)
{
TH0=value/256;
TL0=value%256;
}
unsigned int Timer0_Getcounter()
{
return (TH0<<8)|TL0;
}
void Timer0_run(unsigned char Flag)
{
TR0=Flag;
}
Int0.c
#include<regx52.h>
void int0_init()
{
IT0=1;
IE0=0;
EX0=1;
EA=1;
PX0=1;
}
// void Int0_Routine() interrupt 0
//{
//
//}
3、红外遥控直流电机调速
遥控器按0电机不转,按1,以50%的转速转动; 按2,以80%的转速转动;按3,以100%的转速转动;
main.c
#include<regx52.h>
#include"key.h"
#include"nixie.h"
#include"Motor.h"
#include"IR.h"
unsigned char keynum,speed;
unsigned char command;
void main ()
{
Motor_init();
IR_init();
while(1)
{
if(IR_GetDataFlag())
{
command=IR_GetCommandFlag();
if(command==IR_0){speed=0;}
if(command==IR_1){speed=1;}
if(command==IR_2){speed=2;}
if(command==IR_3){speed=3;}
}
if(speed==0){ Motor_setspeed(0);}
if(speed==1){ Motor_setspeed(50);}
if(speed==2){ Motor_setspeed(80);}
if(speed==3){ Motor_setspeed(100);}
nixie (0,speed);
}
}