单片机14-17

目录

LCD1602

LCD1602液晶显示屏

直流电机驱动(PWM)

LED呼吸灯

直流电机调速

 AD/DA(SPI通信)

AD模数转换

DA数模转换

红外遥控(外部中断)

红外遥控

红外遥控电机调速


LCD1602

单片机14-17_第1张图片

单片机14-17_第2张图片

单片机14-17_第3张图片

单片机14-17_第4张图片

单片机14-17_第5张图片

单片机14-17_第6张图片

单片机14-17_第7张图片

单片机14-17_第8张图片

单片机14-17_第9张图片

单片机14-17_第10张图片

LCD1602液晶显示屏

LCD1602.c

#include 
#include "intrins.h"

sbit LCD_RS = P2^6;//引脚定义
sbit LCD_WR = P2^5;
sbit LCD_EN = P2^7;

#define LCD_DataPort 	P0//寄存器定义,define不要使用分号

void LCD_Delay()		//@11.0592MHz,2ms
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j) ;
	} while (--i);
}


/**
  * @brief  写指令
  * @param  Command	指令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)//写指令
{
	LCD_RS = 0;//1为数据,0为指令
	LCD_WR = 0;//1为读,0为写
	LCD_DataPort = Command;//放入指令
	LCD_EN = 1;//使能
	LCD_Delay();//延时一毫秒
	LCD_EN = 0;//结束使能
	LCD_Delay();
}

/**
  * @brief  写数据
  * @param  Data	数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)//写数据
{
	LCD_RS = 1;//1为数据,0为指令
	LCD_WR = 0;//1为读,0为写
	LCD_DataPort = Data;//放入数据
	LCD_EN = 1;//使能
	LCD_Delay();//延时一毫秒
	LCD_EN = 0;//结束使能
	LCD_Delay();
}

/**
  * @brief  初始化显示屏
  * @param  无
  * @retval 无
  */
void LCD_Init(void) 
{
	LCD_WriteCommand(0x38);//八位数据,两行显示,5*7点阵
	LCD_WriteCommand(0x0C);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//清屏
}

/**
  * @brief  移动光标到目标位置
  * @param  Line行	Column列
  * @retval	无 
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)//设置光标位置
{
	if(Line == 1)
	{
		LCD_WriteCommand(0x80|(Column - 1));//如果是第一行,那么实际地址即为列-1,
		//并设置光标位置,为什么是0x80,地址设置DDRAM
	}
	else
	{
		LCD_WriteCommand(0x80|(Column - 1) + 0x40);//如果是第二行,则进行偏移0x40即为实际地址
		//并设置光标位置
	}
}

/**
  * @brief  显示字符
  * @param  Line	行	
	* @param 	Column	列	
	* @param	Char	显示的字符	
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);//写入数据
}

/**
  * @brief  显示字符串
  * @param  Line	行	
	* @param 	Column	列	
	* @param	String	显示的字符串	
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column, unsigned char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i = 0;String[i] != '\0';i++)//遍历字符串String
	{
		LCD_WriteData(String[i]);//写入数据
	}
}

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result = 1;
	for( i=0;i0 ;i--)
	{
		//LCD_WriteData(0x30 + Num / LCD_Pow(10,i-1)%10);	//获取各位数值并写入显示屏
		LCD_WriteData('0' + Num / LCD_Pow(10,i-1)%10);
		//或者转化为ascii码
	}
}

/**
  * @brief  显示有符号数字
  * @param  Line	行	
	* @param 	Column	列	
	* @param	Num	显示的有符号数字	
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Num,unsigned char Len)
{
	unsigned char i;
	unsigned int Num1;
	LCD_SetCursor(Line,Column);
	if(Num >= 0 )
	{
		LCD_WriteData('+');
		Num1 = Num;
	}
	else{
		LCD_WriteData('-');
		Num1 = -Num;
	}
	for(i=Len ; i>0 ;i--)
	{
		//LCD_WriteData(0x30 + Num / LCD_Pow(10,i-1)%10);	//获取各位数值并写入显示屏
		LCD_WriteData('0' + Num1 / LCD_Pow(10,i-1)%10);
		//或者转化为ascii码
	}
}

/**
  * @brief  显示十六进制数字
  * @param  Line	行	
	* @param 	Column	列	
	* @param	Num	显示的十六进制数字	
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Num,unsigned char Len)
{
	unsigned char i;
	unsigned char SingleNum;
	LCD_SetCursor(Line,Column);
	for(i=Len ; i>0 ;i--)
	{
		SingleNum = Num / LCD_Pow(16,i-1)%16;
		if(SingleNum < 10){
				LCD_WriteData('0' + SingleNum);
			//获取各位数值并写入显示屏
		}
		else
		{
				LCD_WriteData('A' + SingleNum - 10);//修改偏移量
		}
	}
}

/**
  * @brief  显示二进制数字
  * @param  Line	行	
	* @param 	Column	列	
	* @param	Num	显示的二进制数字	
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Num,unsigned char Len)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Len ; i>0 ;i--)
	{
		LCD_WriteData('0' + Num / LCD_Pow(2,i-1)%2);
	} 
}
#include 
#include "LCD1602.h"
#include "Delay.h"

void main(){
		LCD_Init();
	LCD_ShowChar(1,1,'A');//显示字符A
	LCD_ShowString(1,3,"Hello");//显示字符串
	LCD_ShowNum(1,9,66,2);//显示无符号数字
	LCD_ShowSignedNum(1,12,-66,2);//显示有符号数字
	LCD_ShowHexNum(2,1,0xA5,2);//显示十六进制
	LCD_ShowBinNum(2,4,0xA5,8);//显示二进制
	LCD_ShowChar(2,13,0xDF);//显示度数符号
	LCD_ShowChar(2,14,'C');//显示字符C
	
	LCD_ShowString(1,16,"Welcome to China!");
	while( 1 ){
		LCD_WriteCommand(0x18);//流动字幕(指令集)
		Delay(500);
	}

}

直流电机驱动(PWM)

单片机14-17_第11张图片

单片机14-17_第12张图片

单片机14-17_第13张图片单片机14-17_第14张图片

LED呼吸灯

main.c

#include 

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;
				Delay(Time);
				LED = 1;
				Delay(100 - Time);
			}
			
		}
		for(Time = 100; Time > 0;Time--)
		{
			for(i = 0; i < 20;i++)
			{
				LED = 0;
				Delay(Time);
				LED = 1;
				Delay(100 - Time);
			}
			
		}
		
		
	}

}
直流电机调速

main.c

#include 
#include "Delay.h"
#include "Nixie.h"
#include "Key.h"
#include "Timer0.h"

unsigned char Counter,Compare;
unsigned char KeyNum,Speed;
sbit Motor = P1^0;//ULN2003D

void main(){
	Timer0Init();
	//Compare值看自己如何设置,主要看与之比较后你想输出高/低电平,
    //这里是小于输出高电平
	while( 1 ){
		KeyNum = Key();
		if(KeyNum == 1)
		{
			Speed++;
			Speed %= 4;//重置为0
			if(Speed==0){Compare=0;}
			if(Speed==1){Compare=50;}
			if(Speed==2){Compare=75;}
			if(Speed==3){Compare=100;}
		}
		Nixie(1,Speed);
	}

}

void Timer0_Routine() interrupt 1{
	
	TL0 = 0xA4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
//100us定时器

	Counter++;
	Counter %= 100;//将Counter刷新为0
	
	if(Counter < Compare)
	{
		Motor = 1;//高电平转
	}else
	{
		Motor = 0;
	}
}

 AD/DA(SPI通信)

单片机14-17_第15张图片

单片机14-17_第16张图片

单片机14-17_第17张图片

单片机14-17_第18张图片

单片机14-17_第19张图片

单片机14-17_第20张图片

单片机14-17_第21张图片

单片机14-17_第22张图片

单片机14-17_第23张图片

单片机14-17_第24张图片

单片机14-17_第25张图片

单片机14-17_第26张图片

AD模数转换

ET2046.c

#include 
#include "Delay.h"

sbit ET2046_CS = P3^5;
sbit ET2046_DCLK = P3^6;
sbit ET2046_DIN = P3^4;
sbit ET2046_DOUT = P3^7;

/**
  * @brief  相当于当过电阻变化,来输出一些数据
  * @param  Command	控制字
  * @retval ADValue	读取到的数据
  */
unsigned int ET2046_ReadAD(unsigned char Command)//控制字
{
	unsigned char i;
	unsigned int ADValue = 0;
	ET2046_DCLK = 0;
	ET2046_CS = 0;//拉低进入时序
	
	for(i = 0; i<8 ; i++)//发送一个字节
	{
		ET2046_DIN = Command & (0x80 >> i);//获得最高位并将其放入DIN
		ET2046_DCLK = 1;
		ET2046_DCLK = 0;
	}
	for(i = 0; i < 16;i++)//读取两个字节长度
	{
		ET2046_DCLK = 1;
		ET2046_DCLK = 0;
		if(ET2046_DOUT)
		{
			ADValue |= (0x8000>>i);//提前给三位
		}
		Delay(50);
	}
		
	ET2046_CS = 1;//结束时序
	if(Command & 0x08)//查看为什么模式,若得出为1,则是12位。0则为8位
	{
		return ADValue>>8;
	}
	else{
		return ADValue>>4;
	}
}

ET2046.h

#ifndef __ET2046_H__
#define __ET2046_H__

#define ET2046_XP_8				0x9C//0x8C
#define ET2046_YP_8				0xDC
#define ET2046_VBAT_8			0xAC
#define ET2046_AUX_8			0xEC


#define ET2046_XP_12				0x94//0x84
#define ET2046_YP_12				0xD4
#define ET2046_VBAT_12			0xA4
#define ET2046_AUX_12				0xE4

	unsigned int ET2046_ReadAD(unsigned char Command);
#endif

main.c

#include 
#include "LCD1602.h"
#include "Delay.h"
#include "ET2046.h"

unsigned int ADValue;

void main(){
		LCD_Init();
	LCD_ShowString(1,1,"ADJ  NTC  RG");
	
	while( 1 ){
		ADValue = ET2046_ReadAD(ET2046_XP_8);//XP
		LCD_ShowNum(2,1,ADValue,3);
		ADValue = ET2046_ReadAD(ET2046_YP_8);//YP
		LCD_ShowNum(2,6,ADValue,3);
		ADValue = ET2046_ReadAD(ET2046_VBAT_8);//
		LCD_ShowNum(2,11,ADValue,3);
		Delay(10);
	}

}
DA数模转换

main.c

#include 
#include "Delay.h"
#include "Nixie.h"
#include "Key.h"
#include "Timer0.h"

unsigned char Counter,Compare;

sbit DA = P2^1;//DA

unsigned char i;
void main(){
	Timer0Init();
	//Compare值越小LED越暗
	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 = 0xA4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值

	Counter++;
	Counter %= 100;//将Counter刷新为0
	
	if(Counter < Compare)
	{
		DA = 1;
	}else
	{
		DA = 0;
	}
}

红外遥控(外部中断)

单片机14-17_第27张图片

单片机14-17_第28张图片

单片机14-17_第29张图片

单片机14-17_第30张图片

单片机14-17_第31张图片

单片机14-17_第32张图片

单片机14-17_第33张图片

单片机14-17_第34张图片

红外遥控

Int0.c

#include 

/**
  * @brief  外部中断0初始化
  * @param  无
  * @retval 无
  */
void Int0_Init(void)
{
	IT0 = 1;//1下降沿触发,0低电平触发
	IE0 = 0;//中断标志
	EX0 = 1;//打开中断
	EA = 1;//允许所有中断
	PX0	=	1;//中断优先级
}
	
/*外部中断0函数模板
void Int0_Routine(void) interrupt 0
{
	Num++;
	
}	
	

*/

Timer0.c

#include 

/**
  * @brief  定时器0初始化
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)		//1微秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0开始计时
}

/**
  * @brief  定时器0设置计数器值
  * @param  Value,要设置的计数器值,范围:0~65535
  * @retval 无
  */
void Timer0_SetCounter(unsigned int Value)
{
	TH0 = Value / 256;
	TL0 = Value % 256;
}

/**
  * @brief  定时器0获取计数器值
  * @param  无
  * @retval 计数器值,范围:0~65535
  */
unsigned int Timer0_GetCounter(void)
{
	return (TH0 << 8 )| TL0;
}

/**
  * @brief  定时器0启动停止控制
  * @param  Flag 启动停止标志,1为启动,0为停止
  * @retval 无
  */
void Timer0_Run(unsigned char Flag)
{
	TR0 = Flag;
}

IR.c

#include 
#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;
}

void Int0_Routine(void) interrupt 0
{
	if(IR_State == 0)//状态0,下降沿触发
	{
		
		Timer0_SetCounter(0);//定时器清零
		Timer0_Run(1);//定时器启动
		IR_State = 1;//调整状态为1
	}
	else if(IR_State == 1)//为状态1时,等待Start信号或Repeat信号
		{
			IR_Time = Timer0_GetCounter();//获取上次中断到此次中断的时间
			Timer0_SetCounter(0);//便于下次计时
			if(IR_Time > 12442 - 500 && IR_Time < 12442 + 500 )
			{
				IR_State = 2;//置状态为2
			}
			else if(IR_Time > 10368 - 500 && IR_Time < 10368 + 500)//接收到Repeat信号
				{
					IR_RepeatFlag = 1;//连发帧标志为1
					Timer0_Run(0);//停止计时器
					IR_State = 0;//转为空闲
				}
				else{
					IR_State = 1;//搜寻起始信号
				}
		}
		else if(IR_State == 2)//状态2,接收数据
		{
			 IR_Time = Timer0_GetCounter();
			Timer0_SetCounter(0);//获得上个中断到这个中断之间的时间,并立即清零
			if(IR_Time > 1032 - 500 && IR_Time < 1032 + 500 )//如果接收到0
			{
				IR_Data[IR_PData/8] &= ~(0x01<<(IR_PData % 8));//将数据存入IR_Data中(32位),对应数据置0
				IR_PData++;//位置指针自增
			}
			else if(IR_Time > 2250 - 500 && IR_Time < 2250 + 500 )//如果接收到1
			{
				IR_Data[ IR_PData / 8] |= (0x01<<(IR_PData % 8));//将数据对应位置置1,将数据存入IR_Data中
	 			IR_PData++;
			}
			else{
				IR_PData = 0;//数据位置指针清零
				IR_State = 1;//搜寻起始信号
			}
			if(IR_PData >= 32)//如果接收到32位数据
			{
				IR_PData = 0;//数据位置指针清零
				if((IR_Data[0] == ~IR_Data[1]) && (IR_Data[2] == ~IR_Data[3]))//数据验证
				{
					IR_DataFlag = 1;
					IR_Address = IR_Data[0];//存入地址码
					IR_Command = IR_Data[2];//存入命令码
					IR_DataFlag = 1;//接收到数据
				}
				Timer0_Run(0);//停止定时器
				IR_State = 0;//恢复空闲
			}
		}
}	
	

main.c

#include 
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"

unsigned char Num;
unsigned char Address;
unsigned char Command;

void main(){
	LCD_Init();
	LCD_ShowString(1,1,"ADDR   CMD   NUM");
	LCD_ShowString(2,1,"00     00    000");
	
	IR_Init();
	
	while( 1 ){
		if(IR_GetDataFlag() || IR_GetRepeatFlag())//如果收到数据帧或者连续发送
		{
			Address = IR_GetAddress();//获取遥控器地址码
			Command = IR_GetCommand();//获取遥控器命令码
			
			LCD_ShowHexNum(2,1,Address,2);//显示遥控器地址码
			LCD_ShowHexNum(2,8,Command,2);//显示遥控器命令码
			
			if(Command == IR_VOL_MINUS)//如果遥控器VOL-按键按下
			{
				Num --;
			}
			if(Command ==IR_VOL_ADD)//如果遥控器VOL+按键按下
			{
				Num ++;
			}
			LCD_ShowNum(2,14,Num,3);
		}
	}

}
红外遥控电机调速

Timer1.c

#include 

/**
  * @brief  定时器1初始化,100微秒
  * @param  无
  * @retval 无
  */
void Timer1Init(void)		//100微秒@11.0592MHz
{

	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0xA4;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	ET1 = 1;	
	EA = 1;
	PT1 = 0;
}

/*	定时器中断函数模板
void Timer1_Routine() interrupt 3{
	static unsigned int T1Count;
	
	TL0 = 0xA4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	T1Count ++;
	if( T1Count >= 1000 ){
		T1Count = 0;
	}

}
*/

Timer0.c

#include 

/**
  * @brief  定时器0初始化
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)		//1微秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0开始计时
}

/**
  * @brief  定时器0设置计数器值
  * @param  Value,要设置的计数器值,范围:0~65535
  * @retval 无
  */
void Timer0_SetCounter(unsigned int Value)
{
	TH0 = Value / 256;
	TL0 = Value % 256;
}

/**
  * @brief  定时器0获取计数器值
  * @param  无
  * @retval 计数器值,范围:0~65535
  */
unsigned int Timer0_GetCounter(void)
{
	return (TH0 << 8 )| TL0;
}

/**
  * @brief  定时器0启动停止控制
  * @param  Flag 启动停止标志,1为启动,0为停止
  * @retval 无
  */
void Timer0_Run(unsigned char Flag)
{
	TR0 = Flag;
}

Motor.c

#include 
#include "Timer1.h"

sbit Motor = P1^0;//ULN2003D
unsigned char Counter,Compare;

/**
  * @brief  电机初始化
  * @param  无
  * @retval 无
  */
void Motor_Init()
{
	Timer1Init();
}

/**
  * @brief  电机设置速度
  * @param  Speed 要设置的速度,范围0~100
  * @retval 无
  */
void Motor_SetSpeed(unsigned char Speed)
{
	Compare = Speed;
}

void Timer1_Routine() interrupt 3{
	
	TL1 = 0xA4;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值

	Counter++;
	Counter %= 100;//将Counter刷新为0
	
	if(Counter < Compare)
	{
		Motor = 1;//高电平转
	}else
	{
		Motor = 0;
	}
}

main.c

#include 
#include "Delay.h"
#include "Nixie.h"
#include "Key.h"
#include "Motor.h"
#include "IR.h"


unsigned char Command,Speed;


void main(){
	Motor_Init();
	IR_Init();
	while( 1 ){
		
		if(IR_GetDataFlag())//如果收到数据帧
		{
			Command = IR_GetCommand();//获取遥控器命令码
			
			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(75);}
			if(Speed==3){Motor_SetSpeed(100);}
		}
		Nixie(1,Speed);
	}

}

你可能感兴趣的:(单片机,嵌入式硬件)