第十三届蓝桥杯竞赛板CT107D模块驱动

目录

开发板图

锁存器驱动程序

LED模块

数码管模块

独立/矩阵按键模块

DS1302时钟模块

DS18B20温度传感器模块

AT24C02存储器模块

PCF8591数模转换器模块



开发板图

  1. IAP15F2K61S2最小系统
  2. LCD模块
  3. 超声波传感器模块
  4. 红外传感器模块
  5. DS1302时钟模块
  6. AT24C02存储器模块
  7. 74HC138译码器
  8. 74HC02或非门
  9. 数码管模块
  10. DS18B20温度传感器模块
  11. LED模块
  12. 74HC573锁存芯片+ULN2003驱动芯片
  13. CH340串口转USB
  14. 三片74HC573锁存芯片
  15. 蜂鸣器
  16. 继电器
  17. LM386音频功率放大器
  18. NE555N计数器
  19. 独立按键
  20. 矩阵按键
  21. PCF8591数模转换器+LM324四路运算放大器

锁存器驱动程序

译码器锁存器
#define SEL P2

void Open_Lat(int i)//选通某个锁存器
{
	switch (i)
	{
		case 4:SEL=0X9F;break;//不可以用(P2^7=1;P2^6=0;P2^5=0;)这种形式
		case 5:SEL=0XBF;break;//不能一个一个改变,会影响其他的模块
		case 6:SEL=0XDF;break;
		case 7:SEL=0XFF;break;
	}
	Delay1ms();
}

void Close_Lat()//关闭所有锁存器
{
	SEL=0X1F;
	Delay1ms();
}

        可以看到,138译码器的输入端为P2^5,P2^6,P2^7三个引脚。这里我们用宏定义直接将P2定义为SEL,这是因为若使用位定义,必然存在各个位先后改变的问题:例如原本选中锁存器4(P2^7,6,5=100=4),要选中锁存器7(P2^7,6,5=111=7),先将P2^5置一,再将P2^6置一时,就会产生中间态101,这样就会干扰锁存器5

LED模块

锁存器+LED模块
#define LED P0

void Light_One(int i)//点亮某个led
{
	switch (i)//判断LED位选
	{
		case 0:LED=0XFE;break;
		case 1:LED=0XFd;break;
		case 2:LED=0XFb;break;
		case 3:LED=0XF7;break;
		case 4:LED=0Xef;break;
		case 5:LED=0Xdf;break;
		case 6:LED=0Xbf;break;
		case 7:LED=0X7f;break;
	}
	Open_Lat(4);
	Close_Lat();//锁存LED位选
}

void Light_FlowR()//向右流水灯
{
	int i;
	LED=0XFF;//清空LED灯
	Open_Lat(4);
	for(i=0;i<8;i++)
	{
		Light_One(i);
		Delay100ms();
	}
	Close_Lat();
}

void Light_FlowL()//向左流水灯
{
	int i;
	LED=0XFF;//清空LED灯
	Open_Lat(4);
	for(i=7;i>-1;i--)
	{
		Light_One(i);
		Delay100ms();
	}
	Close_Lat();
}

数码管模块

锁存器+数码管模块
int word[]={
//0	  1  	2	3     4    5	6	7	  8	   9//
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
//A	  B	   C	D	  E	  F	   NULL//
0x88,0x83,0xC6,0xA1,0x86,0x8E,0xFF
};//数码管显示的字符库

void Nix_One(int place,int num)//显示某个位置的数码管
{
	LED=word[num];//选定需要显示的字符
	Open_Lat(7);
	Close_Lat();//锁存数码管段选
	switch (place)//判断数码管位选
	{
		case 0:LED=0x01;break;
		case 1:LED=0x02;break;
		case 2:LED=0x04;break;
		case 3:LED=0x08;break;
		case 4:LED=0x10;break;
		case 5:LED=0x20;break;
		case 6:LED=0x40;break;
		case 7:LED=0x80;break;
	}
	Open_Lat(6);
	Close_Lat();//锁存数码管位选
}

独立/矩阵按键模块

独立/矩阵按键模块

#define KEY P3
sbit WR=P4^2;

int Jdg_Sinkey()//判断独立按键
{
	u8 value=0;
	KEY=0XFF;
	if(KEY!=0XFF)
	{
		Delay100us();
		if(KEY!=0XFF)
		{
			switch (KEY)
			{
				case 0xfe:value=7;break;
				case 0xfd:value=6;break;
				case 0xfb:value=5;break;
				case 0xf7:value=4;break;
			}
		}
	}
	return value;
}


int Jdg_Matkey()//转置法判断矩阵按键
{
	u8 value=0;
	KEY=0Xf0;WR=1;//将行置0,列置1
	if(KEY!=0Xf0)
	{
		Delay100us();//消抖
		if(KEY!=0Xf0)
		{
			switch (KEY)
			{
				case 0xe0:value=3;break;//判断列
				case 0xd0:value=2;break;//判断列
			}
		}
	}else if(WR!=1)
	{
		Delay100us();//消抖
		if(WR!=1)
		{
			value=1;//判断列
		}
	}
	
	KEY=0XCF;WR=0;//将列置0,行置1
	if(KEY!=0Xcf)
	{
		Delay100us();//消抖
		if(KEY!=0Xcf)
		{
			switch (KEY)
			{
				case 0xce:value=value;break;//判断行
				case 0xcd:value=value+3;break;//判断行
				case 0xcb:value=value+6;break;//判断行
				case 0xc7:value=value+9;break;//判断行
			}
		}
	}
	return value;
}

DS1302时钟模块

DS1302时钟芯片
读数据时序图写数据时序图
#include "DS1302.h"

u8 WRITE_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//秒分时日月周年//写时间的控制字
u8 READ_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8B,0x8d};//秒分时日月周年//读时间的控制字

u8 DS1302_TIME[7]={0x47,0x22,0x13,0x03,0x07,0x06,0x21};//秒分时日月周年

void DS1302_Write_Byte(u8 addr,u8 dat)//向DS1302写入一个字节数据//参数为控制字和数据
{   
	u8 i=0;
	DS1302_RST=0;
	_nop_();
	DS1302_CLK=0;
	_nop_();
	DS1302_RST=1;
	_nop_();
	
	for(i=0;i<8;i++)
	{
		DS1302_IO=addr&0x01;
		addr>>=1;
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();
	}//写入地址控制字
	
	for(i=0;i<8;i++)
	{
		DS1302_IO=dat&0x01;
		dat>>=1;
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();
	}//写入数据
	DS1302_RST=0;
		_nop_();
}

u8 DS1302_Read_Byte(u8 addr)//向DS1302读出一个字节数据//参数为地址控制字
{
	u8 i=0,dat=0,abit=0;
	
	DS1302_RST=0;
	_nop_();
	DS1302_CLK=0;
	_nop_();
	DS1302_RST=1;
	_nop_();
	
	for(i=0;i<8;i++)
	{
		DS1302_IO=addr&0x01;
		addr>>=1;
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();
	}//写入地址控制字
	
	for(i=0;i<8;i++)
	{
		abit=DS1302_IO;
		dat=(abit<<7)|(dat>>1);
		DS1302_CLK=1;
		_nop_();
		DS1302_CLK=0;
		_nop_();
	}//读出数据
	DS1302_RST=0;
	_nop_();
	return dat;
}	

void DS1302_Init(void)//初始化写入时间
{
	u8 i=0;
	DS1302_Write_Byte(0x8e,0x00);//关闭写保护寄存器
	for(i=0;i<8;i++)
	{
		DS1302_Write_Byte(WRITE_ADDR[i],DS1302_TIME[i]);//写入秒分时日月周年
		
	}
	DS1302_Write_Byte(0x8e,0x80);//打开写保护寄存器
}
void DS1302_Read_Time(void)//读时间
{
	u8 i=0;
	
	for(i=0;i<8;i++)
	{
		DS1302_TIME[i]=DS1302_Read_Byte(READ_ADDR[i]);//读出秒分时日月周年
	}
}

DS18B20温度传感器模块

DS18B20温度传感器
初始化时序图
写/读时序图
void Delay_OneWire(unsigned int t) //延时函数
{
        unsigned char i = 0;
	while(t--){
                for(i=0; i<12; i++);
        }
}

//
void Write_DS18B20(unsigned char dat)//写一个字节数据
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)//读一个字节数据
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}


bit init_ds18b20(void)//初始化函数
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

float ds18b20_read_temperture(void)//读数据
{
	float temp=0;
	u8 dath=0;
	u8 datl=0;
	u16 value=0;
	
	init_ds18b20();//important
	Write_DS18B20(0xcc);//跳过ROM
	Write_DS18B20(0x44);//开始温度变换
	Delay_OneWire(200);
	
	init_ds18b20();//important
	Write_DS18B20(0xcc);//跳过ROM
	Write_DS18B20(0xbe);//读暂存存储器
	datl=Read_DS18B20();//读出低字节
	dath=Read_DS18B20();//读出高字节
	
//合并为16位数据
	value=dath;
	value<<=8;
	value|=datl;
	
	
	if((value&0xf800)==0xf800)//判断符号位,负温度
	{
		value=(~value)+1; //数据取反再加1
		temp=value*(-0.0625);//乘以精度	
	}
	else //正温度
	{
		temp=value*0.0625;	
	}
	return temp;//返回温度
}

void Get_Temp()
{
	int value=0;
	u8 sign=0;
	value=10*ds18b20_read_temperture();
		if(value<0)
		{
			value=-value;
			sign=12;
		}else{
			sign=11;
		}
}

AT24C02存储器模块

AT24C02
I2C总线的应答
写字节读字节

         AT24C02使用的是I2C协议进行通信,因此我们必须对I2C协议具有一定的了解。

        另外,我们还需要注意AT24C02的通信格式:

写字节:

起始信号-写入器件地址(写)-等待应答-写入写入地址-等待应答-写入数据-等待应答-......

读字节:

起始信号-写入器件地址(写)-等待应答-写入读出地址-等待应答-起始信号-写入器件地址(读)-等待应答-读出数据-应答-......

void IIC_Start()//I2C起始信号
{
	IIC_SCL=1;
	IIC_SDA=1;
	delay_10us(1);
	IIC_SDA=0;
	delay_10us(1);
	IIC_SCL=0;
}

void IIC_Stop()//I2C停止信号
{
	IIC_SCL=1;
	IIC_SDA=0;
	delay_10us(1);
	IIC_SDA=1;
	delay_10us(1);
}

void IIC_Ack()//I2C主机应答
{
	IIC_SCL=0;
	IIC_SDA=0;
	delay_10us(1);
	IIC_SCL=1;
	delay_10us(1);
	IIC_SCL=0;
}

void IIC_Nack()//I2C主机非应答
{
	IIC_SCL=0;
	IIC_SDA=1;
	delay_10us(1);
	IIC_SCL=1;
	delay_10us(1);
	IIC_SCL=0;
}

u8 IIC_Wait_Ack()//I2C等待应答
{
	u8 time=0;
	IIC_SCL=1;
	delay_10us(1);
	while(IIC_SDA)
	{
		time++;
		if(time>100)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;
	return 0;
}

void IIC_Write_Byte(u8 dat)//I2C写入一个字节数据
{
	u8 i=0;
	
	IIC_SCL=0;
	for(i=0;i<8;i++)
	{
		if((dat&0x80)>0)
		{
			IIC_SDA=1;
		}else{
			IIC_SDA=0;
		}
		dat<<=1;
		IIC_SCL=1;
		delay_10us(1);
		IIC_SCL=0;
		delay_10us(1);
	}
}

u8 IIC_Read_Byte(u8 ack)//I2C读出一个字节数据(参数决定是否继续)
{
	u8 i =0;
	u8 receive=0;
	
	for(i=0;i<8;i++)
	{
		IIC_SCL=0;
		delay_10us(1);
		IIC_SCL=1;
		delay_10us(1);
		receive<<=1;
		if(IIC_SDA)
		{
			receive++;
		}
	}
	
	if(!ack)
	{
		IIC_Nack();
	}else{
		IIC_Ack();
	}
	
	return receive;
}



void AT24C02_Write_One_Byte(u8 addr,u8 dat)//向AT24C02中地址为addr处写入一个字节数据
{
	IIC_Start();
	IIC_Write_Byte(0xa0);
	IIC_Wait_Ack();
	IIC_Write_Byte(addr);
	IIC_Wait_Ack();
	IIC_Write_Byte(dat);
	IIC_Wait_Ack();
	IIC_Stop();
}

u8 AT24C02_Read_One_Byte(u8 addr)//从AT24C02中地址为addr处读出一个字节数据
{
	u8 i=0;
	IIC_Start();
	IIC_Write_Byte(0xa0);
	IIC_Wait_Ack();
	IIC_Write_Byte(addr);
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Write_Byte(0xa1);
	IIC_Wait_Ack();
	i=IIC_Read_Byte(0);
	IIC_Stop();
	return i;
}



PCF8591数模转换器模块

PCF8591
地址字节
控制字字节

 

u8 ADC_Read(u8 addr)//ADC读出数字信号
{
	u8 dat=0;
	IIC_Start();
	IIC_Write_Byte(0x90);//写入芯片地址(写)
	IIC_Wait_Ack();
	IIC_Write_Byte(addr);//写入通道控制字开始转换
	IIC_Wait_Ack();
	IIC_Start();
	IIC_Write_Byte(0x91);//写入芯片地址(读)
	IIC_Wait_Ack();
	dat=IIC_Read_Byte(0);//读出一个字节数字信号数据
	IIC_Stop();
	return dat;
}

void DAC_Read(u8 dat)//DAC输出模拟信号
{
	IIC_Start();
	IIC_Write_Byte(0x90);//写入芯片地址(写)
	IIC_Wait_Ack();
	IIC_Write_Byte(0x43);//使能通道3的模拟输出
	IIC_Wait_Ack();
	IIC_Write_Byte(dat);//写入需要转换的数字信号
	IIC_Wait_Ack();
	IIC_Stop();
}

 

 


各模块的驱动程序及综合例程笔者将会持续更新

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值