蓝桥杯进阶学习记录——采样光敏电阻和可调电阻的电压

PCF8591是一种具有多功能的4通道A/D和D/A转换器。它具有以下功能特性:
1. 4个独立的模拟输入通道,可以测量电压信号。
2. 一个模拟输出通道,可以输出模拟电压信号。
3. 内置的8位A/D转换器,可以将模拟输入信号转换为数字值。
4. 内置的8位D/A转换器,可以将数字值转换为模拟输出信号。
5. 可以通过IIC总线与微控制器或其他设备进行通信。

PCF8591的设备地址设置如下:
- 如果硬件地址引脚A0、A1、A2均接地,则读操作地址为0x91,写操作地址为0x90。

要读取光敏传感器和电位器的模拟输入信号,需要将相应的控制寄存器写入特定的数据。具体来说,控制寄存器的写入数据应包括以下内容:
- 位7:            固定为0。
- 位6:            0:A/D转换               1:D/A转换
- 位5/位4:    00:四路单端输入
                      01:三路差分输入
                      10:两路单端,一路差分
                      11:两路差分输入
- 位3:           固定为0。
- 位2:           0:禁止自动增量       1:允许自动增量
- 位1/位0:    00:通道0                  01:通道1
                      10:通道2                  11:通道3

 在蓝桥杯单片机设计与开发赛项使用的CT107D单片机开发平台中,PCF8591的三个硬件引脚地址均接地,两路模拟信号均为单端输入,分别是:
      光敏传感器接到AIN1,通道1;控制寄存器应写入:0x01。
      电位器Rb2接到AIN3,通道3;控制寄存器应写入:0x03。

PCF8591 A/D转换应用的开发流程包括以下步骤:
1. 初始化IIC总线。
2. 设置PCF8591的设备地址。
3. 写入控制寄存器,以选择要读取的模拟输入通道。
4. 读取A/D转换结果。
5. 将数字值转换为实际的电压或其他物理量。
icc.c

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/

#include <STC15F2K60S2.H>
#include "intrins.h"
#define DELAY_TIME	5

sbit sda = P2^1;
sbit scl = P2^0;

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

icc.h 

#ifndef _IIC_H
#define _IIC_H
static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
	
#endif

 main.c

#include <STC15F2K60S2.H>
#include "iic.h"

//定义动态显示中单个数码管点亮时长
#define TSMG	500

unsigned char SMG_NoDot[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char SMG_Dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};


unsigned char adc1_value = 0;		//AIN1的采样数据
float adc1_volt = 0;				//AIN1的换算电压
unsigned int smg1_volt = 0;			//AIN1的显示电压
unsigned char adc3_value = 0;		//AIN3的采样数据
float adc3_volt = 0;				//AIN3的换算电压
unsigned int smg3_volt = 0;			//AIN3的显示电压

		
void SELECT_HC138(unsigned char n,unsigned char dat)
{
P0=dat;
P2=(P2&0x1f)|0x00;
  switch(n)
{
	case 4:	P2=(P2&0x1f)|0x80;	break;
	case 5:	P2=(P2&0x1f)|0xa0;	break;
	case 6:	P2=(P2&0x1f)|0xc0;	break;
	case 7:	P2=(P2&0x1f)|0xe0;	break;
}
	P2=(P2&0x1f)|0x00;
}

void DisplaySMG_Bit(unsigned char pos,unsigned char value)
{
	SELECT_HC138(7,0xff);
	
	SELECT_HC138(6,0x01<<pos);
	
	SELECT_HC138(7,value);
	
}

void DisplayAll(unsigned char value)
{
	SELECT_HC138(6,0xff);
	SELECT_HC138(7,value);
}

//===================电压值显示函数===================
void DisplaySMG_ADC()
{
	//数码管右起第0位
	DisplaySMG_Bit(7,SMG_NoDot[smg1_volt	% 10]);
	//数码管右起第1位
	DisplaySMG_Bit(6,SMG_NoDot[(smg1_volt / 10) % 10]);		
	//数码管右起第2位
	DisplaySMG_Bit(5,SMG_Dot[smg1_volt / 100]);				
 
	//数码管右起第5位
	DisplaySMG_Bit(2,SMG_NoDot[smg3_volt	% 10]);
	//数码管右起第6位
	DisplaySMG_Bit(1,SMG_NoDot[(smg3_volt / 10) % 10]);		
	//数码管右起第7位
	DisplaySMG_Bit(0,SMG_Dot[smg3_volt / 100]);		

	DisplayAll(0xff);
}

//===============PCF8591电压采样处理函数===============
//通过I2C总线读取PCF8591模数转换器采集的数据,包括选择通道和读取数据。
unsigned char Read_PCF8591_ADC(unsigned char ain)
{
	unsigned char tmp;
	I2CStart();				//启动i2c通信	
	I2CSendByte(0x90);		//PCF8591的写设备地址,告诉pcf8591要进行写操作
	I2CWaitAck();		//等待设备的应答信号
	
	if(ain == 1)
	{
		I2CSendByte(0x01); //通道1,光敏电阻电压
	}
	else if(ain == 3)
	{
		I2CSendByte(0x03); //通道3,可调电阻电压
	}		
	I2CWaitAck();  						
	I2CStop(); 
	
	DisplaySMG_ADC();			//等待电压转换完成
	
	I2CStart();									
	I2CSendByte(0x91); 	//PCF8591的读设备地址
	I2CWaitAck(); 								
	tmp = I2CReceiveByte(); 	//读出AD采样数据
	I2CSendAck(1);			 	//产生非应答信号,告诉pcf8591不需要再发送数据 								
	I2CStop();
	return tmp;
}
//=============采样光敏电阻和可调电阻的电压=============
//采样AIN1和AIN3通道的数据,并将采样值转换为电压值,最后转换为要显示在数码管上的数据。
void Read_AIN1_AIN3()
{
	adc1_value = Read_PCF8591_ADC(1);//读取通道1的adc值
	adc1_volt = adc1_value * (5.0 / 255);//adc转换成电压值
	smg1_volt = adc1_volt * 100;//转换成整数显示
	
	adc3_value = Read_PCF8591_ADC(3);//读取通道3的值
	adc3_volt = adc3_value * (5.0 / 255);
	smg3_volt = adc3_volt * 100;
}
void initSystem()
{
	SELECT_HC138(4,0xff);
	SELECT_HC138(5,0x00);
	SELECT_HC138(7,0xff);

}
void main()
{

	initSystem();
	while(1)
	{
		Read_AIN1_AIN3();
		DisplaySMG_ADC();	
		
	}

}

  • 18
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
由于具体实现的代码涉及到硬件和编程语言等多方面的内容,这里无法给出完整的代码。但是,我可以提供一些基本的思路和代码片段来帮助你开展工作。 首先,我们需要使用FPGA的开发板和一些外部电路来搭建电压和频率测量的系统。具体来说,需要使用ADC芯片、计数器模块、数码管等元件,以及相应的电阻、电容、晶振等元件来构建电路。这个过程需要根据具体的硬件平台来确定,这里不再赘述。 然后,我们需要在FPGA中编写程序来实现电压和频率的测量功能,并将结果显示在数码管上。这个过程需要使用硬件描述语言(如Verilog、VHDL等)来编写代码,具体的实现过程也需要根据具体的硬件平台来确定。下面是一个简单的Verilog代码片段,可以用来实现计数器模块: ``` module counter( input clk, input reset, output reg [7:0] count ); always @(posedge clk or posedge reset) begin if (reset) begin count <= 0; end else begin count <= count + 1; end end endmodule ``` 这个代码片段定义了一个计数器模块,包括一个时钟输入端、一个复位输入端和一个计数器输出端。当时钟上升沿到来时,计数器的值会加1;当复位信号为高电平时,计数器的值会被重置为0。这个计数器模块可以用于测量输入信号的频率。 最后,需要将电路和程序烧录到FPGA中,然后对系统进行调试和测试,确保电压和频率的测量结果能够正确地显示在数码管上。 希望这个简单的代码片段能够帮助你开展工作。如果需要更详细的帮助,请参考FPGA开发板的用户手册和相关的编程语言教程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值