当前位置: 首页 > news >正文

嵌入式学习--江协51单片机day8

这个本来应该周末写的,可是一直想偷懒,只能是拖到周一了,今天把51结个尾,明天开始学32了。

学习内容LCD1602,直流电机,AD/DA,红外遥控

LCD1602

内部的框架结构

屏幕小于数据显示区,可以实现流动字幕

指令集和时序结构(RS1为数据,0为指令)

void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_E=1;LCD_Delay();LCD_E=0;LCD_Delay();
}
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_E=1;LCD_Delay();LCD_E=0;LCD_Delay();
}

按照时序结构实现数据和指令的写入

在明白数据和指令的写入,我们就可以实现在LCD1602显示各种文本

初始化设置输入模式,显示模式等(指令集中标红)

void LCD_Init(void)
{LCD_WriteCommand(0x38);LCD_WriteCommand(0x0C);LCD_WriteCommand(0x06);LCD_WriteCommand(0x01);
}

设置输入的地址(显示位置)(0x80为DDRAM地址设置)

void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else{LCD_WriteCommand(0x80|(Column-1)+0x40);}
}

剩下的显示字符,字符串等就比较简单了

void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}

实现流动字幕

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
void main()
{LCD_Init();LCD_ShowString(1,16,"Welcome to China!");while(1){LCD_WriteCommand(0x18);Delay(500);}}

直流电机

电机是小车的重要组成部分(重要性不必多说了吧)(端午会出小车代码,已经在路上了)

LED呼吸灯

#include <REGX52.H>sbit LED=P2^0;void Delay(unsigned int t)
{while(t--);
}void main()
{unsigned char Time,i;while(1){for(Time=0;Time<100;Time++)		//改变亮灭时间,由暗到亮{for(i=0;i<20;i++)			//计次延时{LED=0;					//LED亮Delay(Time);			//延时TimeLED=1;					//LED灭Delay(100-Time);		//延时100-Time}}for(Time=100;Time>0;Time--)		//改变亮灭时间,由亮到暗{for(i=0;i<20;i++)			//计次延时{LED=0;					//LED亮Delay(Time);			//延时TimeLED=1;					//LED灭Delay(100-Time);		//延时100-Time}}}
}

直流电机调速

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Timer0.h"sbit Motor=P1^0;unsigned char Counter,Compare;	//计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed;void main()
{Timer0_Init();while(1){KeyNum=Key();if(KeyNum==1){Speed++;Speed%=4;if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比if(Speed==1){Compare=50;}if(Speed==2){Compare=75;}if(Speed==3){Compare=100;}}Nixie(1,Speed);}
}void Timer0_Routine() interrupt 1
{TL0 = 0x9C;		//设置定时初值TH0 = 0xFF;		//设置定时初值Counter++;Counter%=100;	//计数值变化范围限制在0~99if(Counter<Compare)	//计数值小于比较值{Motor=1;		//输出1}else				//计数值大于比较值{Motor=0;		//输出0}
}

AD/DA转换

ADAnalog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号

DADigital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号

像是温度传感器就是AD,将外部温度的变化(模拟信号)转换为电压变化(数字信号)

蜂鸣器就是DA,我们将谱子对应的编码写入,将内部电流的变化(数字信号)转换为震动(模拟信号)

右下是一个负反馈的放大器

从右边看,2R和2R并联是R,R和R串联是2R,循环往复。I就是VREF/R,I1=2*I0,递推I=256*I0。流经运算放大器Rfb的电流是D7~D0的和,V0等于Rfb乘流经电流

所以很少用DA,大多都是通过PWM实现

IN传递进来电压,然后通过比较器和VREF比较,调整VREF逐次逼近,最后输出

AD模数转换

XPT2064是A/D转换器

#include <REGX52.H>
#include <INTRINS.H>//引脚定义
sbit XPT2046_DIN=P3^4;
sbit XPT2046_CS=P3^5;
sbit XPT2046_DCLK=P3^6;
sbit XPT2046_DOUT=P3^7;/*** @brief  ZPT2046读取AD值* @param  Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数* @retval AD转换后的数字量,范围:8位为0~255,12位为0~4095*/
unsigned int XPT2046_ReadAD(unsigned char Command)
{unsigned char i;unsigned int Data=0;XPT2046_DCLK=0;XPT2046_CS=0;for(i=0;i<8;i++){XPT2046_DIN=Command&(0x80>>i);XPT2046_DCLK=1;XPT2046_DCLK=0;}for(i=0;i<16;i++){XPT2046_DCLK=1;XPT2046_DCLK=0;if(XPT2046_DOUT){Data|=(0x8000>>i);}}XPT2046_CS=1;return Data>>8;
}
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "XPT2046.h"unsigned int ADValue;void main(void)
{LCD_Init();LCD_ShowString(1,1,"ADJ  NTC  GR");while(1){ADValue=XPT2046_ReadAD(XPT2046_XP);		//读取AIN0,可调电阻LCD_ShowNum(2,1,ADValue,3);				//显示AIN0ADValue=XPT2046_ReadAD(XPT2046_YP);		//读取AIN1,热敏电阻LCD_ShowNum(2,6,ADValue,3);				//显示AIN1ADValue=XPT2046_ReadAD(XPT2046_VBAT);	//读取AIN2,光敏电阻LCD_ShowNum(2,11,ADValue,3);			//显示AIN2Delay(100);}
}

红外遥控

#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"unsigned int IR_Time;
unsigned char IR_State;unsigned char IR_Data[4];
unsigned char IR_pData;unsigned char IR_DataFlag;
unsigned char IR_RepeatFlag;
unsigned char IR_Address;
unsigned char IR_Command;/*** @brief  红外遥控初始化* @param  无* @retval 无*/
void IR_Init(void)
{Timer0_Init();Int0_Init();
}/*** @brief  红外遥控获取收到数据帧标志位* @param  无* @retval 是否收到数据帧,1为收到,0为未收到*/
unsigned char IR_GetDataFlag(void)
{if(IR_DataFlag){IR_DataFlag=0;return 1;}return 0;
}/*** @brief  红外遥控获取收到连发帧标志位* @param  无* @retval 是否收到连发帧,1为收到,0为未收到*/
unsigned char IR_GetRepeatFlag(void)
{if(IR_RepeatFlag){IR_RepeatFlag=0;return 1;}return 0;
}/*** @brief  红外遥控获取收到的地址数据* @param  无* @retval 收到的地址数据*/
unsigned char IR_GetAddress(void)
{return IR_Address;
}/*** @brief  红外遥控获取收到的命令数据* @param  无* @retval 收到的命令数据*/
unsigned char IR_GetCommand(void)
{return IR_Command;
}//外部中断0中断函数,下降沿触发执行
void Int0_Routine(void) interrupt 0
{if(IR_State==0)				//状态0,空闲状态{Timer0_SetCounter(0);	//定时计数器清0Timer0_Run(1);			//定时器启动IR_State=1;				//置状态为1}else if(IR_State==1)		//状态1,等待Start信号或Repeat信号{IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间Timer0_SetCounter(0);	//定时计数器清0//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)if(IR_Time>13500-500 && IR_Time<13500+500){IR_State=2;			//置状态为2}//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)else if(IR_Time>11250-500 && IR_Time<11250+500){IR_RepeatFlag=1;	//置收到连发帧标志位为1Timer0_Run(0);		//定时器停止IR_State=0;			//置状态为0}else					//接收出错{IR_State=1;			//置状态为1}}else if(IR_State==2)		//状态2,接收数据{IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间Timer0_SetCounter(0);	//定时计数器清0//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)if(IR_Time>1120-500 && IR_Time<1120+500){IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0IR_pData++;			//数据位置指针自增}//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)else if(IR_Time>2250-500 && IR_Time<2250+500){IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1IR_pData++;			//数据位置指针自增}else					//接收出错{IR_pData=0;			//数据位置指针清0IR_State=1;			//置状态为1}if(IR_pData>=32)		//如果接收到了32位数据{IR_pData=0;			//数据位置指针清0if((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}}
}

接收数据时32位,通过IR_pData控制哪个八位数据的哪一位

时间不会很精准,留下500误差(注意不要让两种状态交叉就行,比如start和repeat差值是2000,repeat+500和start-500就不会交叉)

由于对时间的要求比较高,我们需要通过外部中断确保信号被接收

void Int0_Init(void)
{IT0=1;IE0=0;EX0=1;EA=1;PX0=1;
}

今日语录:当开始的热情褪去,剩下的一切都变得裸露,是懒惰,是气馁,是焦虑。

相关文章:

  • 卷积神经网络基础(九)
  • Vue-样式绑定-class
  • liunx定时任务,centos定时任务
  • 前端工程的相关管理 git、branch、build
  • Git上传项目到GitHub
  • 企业销售管理痛点解析与数字化解决方案
  • CVE-2015-1422 Gecko CMS CSRF添加管理员
  • JVM的垃圾回收机制
  • c/c++的opencv均值函数
  • 盲盒APP开发——解锁盲盒经济无限可能
  • 机器学习(14)——模型调参
  • ThreadLocal 源码深度解析
  • 【线下沙龙】NineData x Apache Doris x 阿里云联合举办数据库技术Meetup,5月24日深圳见!
  • YoloV8改进策略:卷积篇|风车卷积|即插即用
  • 【无用知识】如何做到高效率
  • 今日行情明日机会——20250519
  • 【MySQL成神之路】MySQL常用语法总结
  • 聊聊更新中断和更新事件那些事儿
  • Unity预制体变体(Prefab Variants)、接口(Interface)、抽象类(Abstract Class)、枚举(Enumeration)
  • 计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 13.几何着色器(二)爆炸效果修改图元类型
  • 特朗普与普京开始进行电话会谈,稍后还将致电泽连斯基
  • 43.2℃!河南林州打破全省5月最高温纪录,明后天高温将持续
  • 莱布雷希特专栏:古典乐坛边缘人
  • 520、521婚登预约迎高峰?上海民政:将增派力量,新人可现场办理
  • 墨海军训练舰在纽约撞桥,墨总统:对遇难者表示悲痛,将跟进调查
  • 曾毓群说未来三年重卡新能源渗透率将突破50%,宁德时代如何打好换电这张牌