目录
一、相关知识
1.关于PCF8591(这里只是简述,详细专业的介绍还需参考芯片手册)
2.PCF8591控制寄存器
3.AD的位数
4.分辨率
5.AD转换的原理
6.注意事项
7.PCF8591转化函数范例
①光敏电阻AD转化函数
②滑动电阻AD转化函数
二、所要实现的功能
三、代码实现
1.参数定义
2.138译码器通道选择函数
3.初始化系统
4.延时函数
5.单个数码管显示函数
6.数码管动态显示
7.光敏电阻RD1 AD转换函数
8.可调电阻RB2 AD转换函数
9.按键控制函数
10.按键切换状态函数
11.完整代码
四、运行图片
关于共阳数码管等部分已在之前的文章中介绍过了,此处不再介绍了。
需要用到的芯片手册和驱动文件都已上传资源可以自行免费下载使用!
【免费】蓝桥杯最新驱动文件包括onewire、iic、ds1302资源-CSDN文库
【免费】蓝桥杯单片机开发及应用的中英两版芯片手册资源-CSDN文库
一、相关知识
1.关于PCF8591(这里只是简述,详细专业的介绍还需参考芯片手册)
PCF8591是具有I2C总线接口的8位A/D及D/A转换器。有4路A/D转换输入,1路D/A模拟输出。这就是说,它既可以作A/D 转换也可以作D/A转换。A/D转换为逐次比较型。
2.PCF8591控制寄存器
I2C总线系统中的每一片PCF8591通过发送有效地址到该器件来激活。该地址包括固定部分和可编程部分。可编程部分必须根据地址引脚A0、A1和A2来设置。在I2C总线协议中地址必须是起始条件后作为第一个字节发送。地址字节的最后一位是用于设置以后数据传输方向的读/写位。
3.AD的位数
AD的位数表明这个AD共有2^n个刻度。8位AD,输出的刻度是0~255。PCF8591中的“8”就表示是8为精度的,因此它的数字数据在0~255之间。
4.分辨率
分辨率就是AD能够分辨的最小的模拟量的变化,假设5.10V的系统采用的8位AD采样,那么它能分辨的最小电压就是5.10/255=0.02V。
5.AD转换的原理
介绍完分辨率再来介绍AD转换的原理。AD转换的原理简单来理解就是通过电路将非电信号转换为电信号,然后通过一个基准电压(PCF8591的基准电压是5V),判断这个电信号的电压高低,然后得到一个0~255(8位精度)的比值。
分辨率中提到的5.10V就可以看作是取整之后得到的5V。
6.注意事项
①省赛中用的最多的是通道1和通道3:
光敏传感器RD1接到AIN1,通道1,因此控制寄存器应在A0~A2处写入0x01;
滑动变阻器Rb2接到AIN3,通道3,因此控制寄存器应在A0~A2处写入0x03。
7.PCF8591转化函数范例
写代码时可直接套用。
①光敏电阻AD转化函数
// 光敏电阻RD1 AD转换函数
void Read_RD1(void)
{
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x90 ); // PCF8591的 写 设备地址
IIC_WaitAck(); // 等待从机应答
IIC_SendByte( 0x01 ); // 发送PCF8591的控制字节,选择模拟量输入通道,光敏传感器相应的控制寄存器写入0x01
IIC_WaitAck(); // 等待从机应答
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 , data_RD1 ); // 数码管显示
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x91 ); // PCF8591的 读 设备地址
IIC_WaitAck(); // 等待从机应答
data_RD1 = IIC_RecByte(); // 从i2c总线上接收数据
IIC_SendAck( 1 ); // 产生非应答信号
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 ,data_RD1 ); // 数码管显示
}
②滑动电阻AD转化函数
// 可调电阻RB2 AD转换函数
void Read_RB2(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
SMG_Show( 3 , data_RB2 );
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
data_RB2 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
SMG_Show( 3 , data_RB2 );
}
二、所要实现的功能
用PCF8591进行AD转换。在开机时不显示数据,在按下S7按键时,转换为通道1,光敏电阻转换通道,通过遮挡和不遮挡光敏电阻RD1,来观察数码管上显示的数值变化是否正确;在按下S6按键时,转换为通道3,滑动电阻转换通道,通过拧滑动电阻RB2,来观察数码管上显示的数值变化是否正确。
三、代码实现
1.参数定义
#include <STC15F2K60S2.H>
#include "Delay_ms.h"
#include "iic.h"
sbit S7 = P3^0; // 定义按键
sbit S6 = P3^1;
unsigned char data_RD1 = 0; // 光敏电阻
unsigned char data_RB2 = 0; // 滑动电阻
unsigned char flag = 0; // 标志位
// 不加 “code” 会影响单片机运行速度,会改变RAM,加了 code 之后內容就固定不变了,不会占用RAM
unsigned char code SMG_Duanma[19] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0x00
}; // 0~F - . 全部
// 带点显示的数字
unsigned char code SMG_Dian[10] =
{
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10
}; // 0.~9.
2.138译码器通道选择函数
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = (P2 & 0x1f) | 0x00; // 0
break;
case 4:
P2 = (P2 & 0x1f) | 0x80; // Y4C
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; // Y5C
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; // Y6C
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; // Y7C
break;
}
}
3.初始化系统
// 初始化系统
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
4.延时函数
void Delay_tms( unsigned int t )
{
int i;
while( t-- )
{
for( i=115 ; i>0 ; i-- )
{}
}
}
5.单个数码管显示函数
// 数码管显示
void SMG_Light( unsigned char pos , unsigned char dat)
{
HC138_Init( 6 );
P0 = 0x01 << pos;
HC138_Init( 7 );
P0 = dat;
}
6.数码管动态显示
// 数码管动态显示
void SMG_Show( unsigned char channel , unsigned char dat )
{
SMG_Light( 0 , SMG_Duanma[12] ); // C
Delay_tms( 10 );
SMG_Light( 1 , 0x89 ); // H
Delay_tms( 10 );
SMG_Light( 2 , SMG_Duanma[channel] ); // 显示AD转换的通道号
Delay_tms( 10 );
SMG_Light( 3 , 0xff );
SMG_Light( 4 , 0xff );
SMG_Light( 5 , SMG_Duanma[dat / 100] );
Delay_tms( 10 );
SMG_Light( 6 , SMG_Duanma[dat / 10 % 10] );
Delay_tms( 10 );
SMG_Light( 7 , SMG_Duanma[dat % 10] );
Delay_tms( 10 );
}
7.光敏电阻RD1 AD转换函数
// 光敏电阻RD1 AD转换函数
void Read_RD1(void)
{
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x90 ); // PCF8591的 写 设备地址
IIC_WaitAck(); // 等待从机应答
IIC_SendByte( 0x01 ); // 发送PCF8591的控制字节,选择模拟量输入通道,光敏传感器相应的控制寄存器写入0x01
IIC_WaitAck(); // 等待从机应答
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 , data_RD1 ); // 数码管显示
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x91 ); // PCF8591的 读 设备地址
IIC_WaitAck(); // 等待从机应答
data_RD1 = IIC_RecByte(); // 从i2c总线上接收数据
IIC_SendAck( 1 ); // 产生非应答信号
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 ,data_RD1 ); // 数码管显示
}
8.可调电阻RB2 AD转换函数
// 可调电阻RB2 AD转换函数
void Read_RB2(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
SMG_Show( 3 , data_RB2 );
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
data_RB2 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
SMG_Show( 3 , data_RB2 );
}
9.按键控制函数
// 按键更改AD转换方式
void Key_Scan(void)
{
if( S7 == 0 )
{
Delay_tms( 20 );
if( S7 == 0 )
{
while( S7 == 0 );
flag = 1;
}
}
if( S6 == 0 )
{
Delay_tms( 20 );
if( S6 == 0 )
{
while( S6 == 0 );
flag = 2;
}
}
}
10.按键切换状态函数
// 处理按键的状态
void Key_Deal(void)
{
// S7为光敏电阻
if( flag == 1 )
{
Read_RD1();
}
// S6为可调电阻
else if( flag == 2 )
{
Read_RB2();
}
}
11.完整代码
#include <STC15F2K60S2.H>
#include "Delay_ms.h"
#include "iic.h"
sbit S7 = P3^0; // 定义按键
sbit S6 = P3^1;
unsigned char data_RD1 = 0; // 光敏电阻
unsigned char data_RB2 = 0; // 滑动电阻
unsigned char flag = 0; // 标志位
// 不加 “code” 会影响单片机运行速度,会改变RAM,加了 code 之后內容就固定不变了,不会占用RAM
unsigned char code SMG_Duanma[19] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0x00
}; // 0~F - . 全部
// 带点显示的
unsigned char code SMG_Dian[10] =
{
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10
}; // 0.~9.
// 通道选择函数
void HC138_Init( unsigned char channel )
{
switch( channel )
{
case 0:
P2 = (P2 & 0x1f) | 0x00; // 0
break;
case 4:
P2 = (P2 & 0x1f) | 0x80; // Y4C
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0; // Y5C
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0; // Y6C
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0; // Y7C
break;
}
}
// 关闭蜂鸣器和继电器
void System_Init(void)
{
// 关闭LED灯
HC138_Init( 4 );
P0 = 0xff;
// 关闭蜂鸣器和继电器
HC138_Init( 5 );
P0 = 0xaf; // 1010 1111
// 关闭通道选择
HC138_Init( 0 );
}
// 数码管显示
void SMG_Light( unsigned char pos , unsigned char value )
{
HC138_Init( 6 );
P0 = 0x01 << pos;
HC138_Init( 7 );
P0 = value;
}
// 数码管动态显示
void SMG_Show( unsigned char channel , unsigned char dat )
{
SMG_Light( 0 , SMG_Duanma[12] ); // C
Delay_tms( 10 );
SMG_Light( 1 , 0x89 ); // H
Delay_tms( 10 );
SMG_Light( 2 , SMG_Duanma[channel] ); // 显示AD转换的通道号
Delay_tms( 10 );
SMG_Light( 3 , 0xff );
SMG_Light( 4 , 0xff );
SMG_Light( 5 , SMG_Duanma[dat / 100] );
Delay_tms( 10 );
SMG_Light( 6 , SMG_Duanma[dat / 10 % 10] );
Delay_tms( 10 );
SMG_Light( 7 , SMG_Duanma[dat % 10] );
Delay_tms( 10 );
}
// 光敏电阻RD1 AD转换函数
void Read_RD1(void)
{
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x90 ); // PCF8591的 写 设备地址
IIC_WaitAck(); // 等待从机应答
IIC_SendByte( 0x01 ); // 发送PCF8591的控制字节,选择模拟量输入通道,光敏传感器相应的控制寄存器写入0x01
IIC_WaitAck(); // 等待从机应答
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 , data_RD1 ); // 数码管显示
IIC_Start(); // i2c总线起始信号
IIC_SendByte( 0x91 ); // PCF8591的 读 设备地址
IIC_WaitAck(); // 等待从机应答
data_RD1 = IIC_RecByte(); // 从i2c总线上接收数据
IIC_SendAck( 1 ); // 产生非应答信号
IIC_Stop(); // i2c总线停止信号
SMG_Show( 1 ,data_RD1 ); // 数码管显示
}
// 可调电阻RB2 AD转换函数
void Read_RB2(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
SMG_Show( 3 , data_RB2 );
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
data_RB2 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
SMG_Show( 3 , data_RB2 );
}
// 按键更改AD转换方式
void Key_Scan(void)
{
if( S7 == 0 )
{
Delay_tms( 20 );
if( S7 == 0 )
{
while( S7 == 0 );
flag = 1;
}
}
if( S6 == 0 )
{
Delay_tms( 20 );
if( S6 == 0 )
{
while( S6 == 0 );
flag = 2;
}
}
}
// 处理按键的状态
void Key_Deal(void)
{
// S7为光敏电阻
if( flag == 1 )
{
Read_RD1();
}
// S6为可调电阻
else if( flag == 2 )
{
Read_RB2();
}
}
int main(void)
{
System_Init();
while(1)
{
Key_Scan();
Key_Deal();
}
}
四、运行图片