蓝桥杯单片机之模块代码《DA》

过往历程

历程1:秒表

历程2:按键显示时钟

历程3:列矩阵按键显示时钟

历程4:行矩阵按键显示时钟

历程5:新DS1302

历程6:小数点精确后两位ds18b20

历程7:35定时器测量频率

历程8:AT24C02

历程9:AT24C02秒表

历程10:AD

历程11:超声波

历程12:多样点灯方式

历程13:AT24C02页写入



PCF8591

  PCF8591是具有I2C总线接口的8位A/D及D/A转换器。有4路A/D转换输入,1路D/A模拟输出。这就是说,它既可以作A/D 转换也可以作D/A转换。A/D转换为逐次比较型。
在这里插入图片描述
在这里插入图片描述
  I2C总线系统中的每一片PCF8591通过发送有效地址到该器件来激活。该地址包括固定部分和可编程部分。可编程部分必须根据地址引脚A0、A1和A2来设置。在I2C总线协议中地址必须是起始条件后作为第一个字节发送。地址字节的最后一位是用于设置以后数据传输方向的读/写位。

A/D 重要指标

1、ADC 的位数
  一个 n 位的 ADC 表示这个 ADC 共有 2 的 n 次方个刻度。8 位的 ADC,输出的是从 0~255 一共 256 个数字量,也就是 2 的 8 次方个数据刻度。
  AD的位数表明这个AD共有2^n个刻度。8位AD,输出的刻度是0255。PCF8591中的“8”就表示是8为精度的,因此它的数字数据在0255之间。

2、基准源
  基准源,也叫基准电压,是 ADC 的一个重要指标,要想把输入 ADC 的信号测量准确,那么基准源首先要准,基准源的偏差会直接导致转换结果的偏差。比如一根米尺,总长度本应该是 1 米,假定这根米尺被火烤了一下,实际变成了 1.2 米,再用这根米尺测物体长度的话自然就有了较大的偏差。假如我们的基准源应该是 5.10V,但是实际上提供的却是 4.5V,这样误把 4.5V 当成了 5.10V 来处理的话,偏差也会比较大。

3、分辨率
  分辨率是数字量变化一个最小刻度时,模拟信号的变化量,定义为满刻度量程与 2^n -1 的比值。假定 5.10V 的电压系统,使用 8 位的 ADC 进行测量,那么相当于 0~255 一共 256 个刻度把 5.10V 平均分成了 255 份,那么分辨率就是 5.10/255 = 0.02V。

AD转换的原理

  介绍完分辨率再来介绍AD转换的原理。AD转换的原理简单来理解就是通过电路将非电信号转换为电信号,然后通过一个基准电压(PCF8591的基准电压是5V),判断这个电信号的电压高低,然后得到一个0~255(8位精度)的比值。
省赛中用的最多的是通道1和通道3:

                    光敏传感器RD1接到AIN1,通道1,因此控制寄存器应在A0~A2处写入0x01;

                    滑动变阻器Rb2接到AIN3,通道3,因此控制寄存器应在A0~A2处写入0x03。

前期准备

1:本文使用的头文件是由stc生成
在这里插入图片描述
点击保存文件之后,保存至自己文件目录下方即可
在这里插入图片描述
2:本文使用的都是官方提供的底层驱动代码
在这里插入图片描述

驱动处理

AD转换/DA转换

官方提供的程序

//c文件
#include "iic.h"

#define DELAY_TIME 5

//I2C总线内部延时函数
void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}

//I2C总线启动信号
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//I2C总线停止信号
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答或非应答信号
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//I2C总线发送一个字节数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//I2C总线接收一个字节数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}

//头文件
#ifndef _IIC_H
#define _IIC_H

#include "reg52.h"
#include "intrins.h"

sbit SDA = P2^1;
sbit SCL = P2^0;

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

#endif

自己需要更改的地方

1:同样这个是与ds1302一样,只需要添加上中断即可

#include "iic.h"

#define DELAY_TIME 5

//I2C总线内部延时函数
void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}

//I2C总线启动信号
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//I2C总线停止信号
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答或非应答信号
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//I2C总线发送一个字节数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
		EA=0;							//关闭中断
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
			EA=1;					//开启中断
    }
    SCL  = 0;  
}

//I2C总线接收一个字节数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
			EA=0;			//关闭中断
    	SCL = 1;	
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
			EA=1;		//开启中断
    }
    return da;    
}


总代码

#include "stc15f2k.h"
#include "iic.h"
char dula[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
char disdula[]={0,0,0,0,0,0,0,0};

unsigned int date_5v,date_ad;

bit flag_speed;

void buzz()
{
	P2=((P2&0X1F)|0XA0);
	P0=0X00;
	P2&=0X1F;
	
	P2=((P2&0X1F)|0X80);
	P0=0XFF;
	P2&=0X1F;
}

void din()
{
	AUXR &= 0xBF;		//?????12T??
	TMOD &= 0x0F;		//???????
	TL1 = 0x66;		//??????
	TH1 = 0xFC;		//??????
	TF1 = 0;		//??TF1??
	TR1 = 1;		//???1????
	EA=1;
	ET1=1;
}

void display()
{
	static int diswela;
	
	P2=((P2&0X1F)|0Xe0);
	P0=0XFF;
	P2&=0X1F;
	
	P2=((P2&0X1F)|0Xc0);
	P0=1<<diswela;
	P2&=0X1F;
	
	P2=((P2&0X1F)|0Xe0);
	P0=dula[disdula[diswela]];
	P2&=0X1F;
	
	if(++diswela>=8)diswela=0;
}

void display_da()
{
	disdula[0]=date_ad/100%10;
	disdula[1]=date_ad/10%10;
	disdula[2]=date_ad/1%10;
	disdula[3]=11;
	disdula[4]=11;
	disdula[5]=12+date_5v/100%10;
	disdula[6]=date_5v/10%10;
	disdula[7]=date_5v/1%10;
}

void da(int date)
{
	
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(0x43);
	IIC_WaitAck();
	IIC_SendByte(date);
	IIC_SendAck(1);
	IIC_Stop();
	
	date_5v=date*1.96;
}
void ad()
{
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(0x03);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	date_ad=IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
}

void da_output()
{
	da(date_ad);
}
	
void main()
{
	buzz();
	din();
	while(1)
	{
		display_da();
		if(flag_speed==1)
		{
		flag_speed=0;	
		ad();
		da_output();
		}
		
	}
}

void qa() interrupt 3
{
	static int ms;
	
	if(!(ms%100))flag_speed=1;
	if(++ms>=1500)ms=0;
	
	display();
}

省赛代码传送门

第三届蓝桥杯单片机省赛
第四届蓝桥杯单片机省赛
第五届蓝桥杯单片机省赛
第六届蓝桥杯单片机省赛
第七届蓝桥杯单片机省赛
第八届蓝桥杯单片机省赛
第九届蓝桥杯单片机省赛
第十届蓝桥杯单片机省赛
第十一届蓝桥杯单片机省赛

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值