一、初始化外设:
![](https://i-blog.csdnimg.cn/blog_migrate/4aea8fd3ef7db41d5b25c46fe25e2495.png)
数码管(定时器)、计数器、独立按键、PCF8591、LED
新建工程
(1)主函数:
#ifndef MAIN_H
#define MAIN_H
#include "Public.h"
#endif
#include "main.h"
void SEG_Proc();
void main()
{
All_Close();
Timer1_Init();
while(1)
{
SEG_Proc();
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
// sprintf(COT,"F %6u",(u16)6000);
sprintf(COT,"U %1.2f",3.41);
SEG_TSL(COT,C0D);
}
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
}
(2)公共函数:
#ifndef PUBLIC_H
#define PUBLIC_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Elect(u8 cs,u8 e_data);
void All_Close();
#endif
#include "Public.h"
/*
选择锁存器,传输数据
*/
void Elect(u8 cs,u8 e_data)
{
P0 = e_data;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void All_Close()
{
//关闭蜂鸣器和继电器
Elect(5,0x00);
//关闭LED
Elect(4,0xff);
//关闭数码管
Elect(7,0xff);
}
数码管:
![](https://i-blog.csdnimg.cn/blog_migrate/bd3fbb4ea07e30204960f8a006084c81.png)
![](https://i-blog.csdnimg.cn/blog_migrate/42553c085a52a85293e8fb7f324a0678.png)
(1)主函数:
#ifndef MAIN_H
#define MAIN_H
#include "Public.h"
#include "SIMP_DVI.h"
#include "SEG.h"
#include "stdio.h"
//数码管
u16 seg_delay;
u8 COT[10],C0D[8],PSI;
#endif
#include "main.h"
void SEG_Proc();
void main()
{
All_Close();
Timer1_Init();
while(1)
{
SEG_Proc();
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
// sprintf(COT,"F %6u",(u16)6000);
sprintf(COT,"U %1.2f",3.41);
SEG_TSL(COT,C0D);
}
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
}
(2)数码管:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *imput,u8 *output);
void SEG_Show(u8 COD,u8 PSI);
#endif
#include "SEG.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
/*
输入字符串,输出数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0,j=0;
for(i=0;i<8;i++,j++)
{
switch(input[j])
{
case '0': output[i] = Seg_Table[0];break;
case '1': output[i] = Seg_Table[1];break;
case '2': output[i] = Seg_Table[2];break;
case '3': output[i] = Seg_Table[3];break;
case '4': output[i] = Seg_Table[4];break;
case '5': output[i] = Seg_Table[5];break;
case '6': output[i] = Seg_Table[6];break;
case '7': output[i] = Seg_Table[7];break;
case '8': output[i] = Seg_Table[8];break;
case '9': output[i] = Seg_Table[9];break;
case 'F': output[i] = Seg_Table[15];break;
case 'U': output[i] = ~0x3e;break;//~00111110
default:output[i] = 0xff;
}
if(input[j+1] == '.')
{
output[i] &= ~0x80;
j++;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消隐
Elect(7,0xff);
//位选
Elect(6,0x01<<PSI);
//段选
Elect(7,COD);
}
(3)定时器
#ifndef SIMP_DVI_H
#define SIMP_DVI_H
#include "Public.h"
void Timer1_Init(void);
#endif
#include "SIMP_DVI.h"
/*
定时器1
*/
void Timer1_Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA = 1;
}
独立按键:
(1)部分主函数:
void main()
{
All_Close();
Timer1_Init();
while(1)
{
Key_Proc();
// SEG_Proc();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10) key_delay = 0;
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_down=0;
if(key_delay)return;
key_delay = 1;
key_now = D_Key();
key_down = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_down)
{
sprintf(COT,"%u",(u16)key_down);
SEG_TSL(COT,C0D);
}
}
(2)按键检测函数:
#ifndef SIMP_DVI_H
#define SIMP_DVI_H
#include "Public.h"
void Timer1_Init(void);
u8 D_Key();
#endif
/*
独立按键按键检测
*/
u8 D_Key()
{
u8 i=0;
for(i=0;i<4;i++)
if((P3 & (0x08>>i)) == 0)
return i+4;
return 0;
}
LED:
(1)部分主函数:
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10) key_delay = 0;
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Show(l_data);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_down=0;
if(key_delay)return;
key_delay = 1;
key_now = D_Key();
key_down = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_down)
{
l_data = 0x01<<(key_down-4);
}
}
(2)LED显示函数:
#ifndef SIMP_DVI_H
#define SIMP_DVI_H
#include "Public.h"
void Timer1_Init(void);
u8 D_Key();
void LED_Show(u8 l_data);
#endif
/*
根据输入的数据显示LED,1为亮灯
*/
void LED_Show(u8 l_data)
{
Elect(4,~l_data);
}
计数器:
(1)部分主函数:
void main()
{
All_Close();
Timer1_Init();
Timer0_Init();
while(1)
{
// Key_Proc();
SEG_Proc();
}
}
void Timer1_Isr(void) interrupt 3
{
count_ms++;
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10) key_delay = 0;
if(count_ms == 1000)
{
freq_num = (TH0<<8) | TL0;
count_ms = 0;
TH0 = 0;
TL0 = 0;
}
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Show(l_data);
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
sprintf(COT,"F %6u",freq_num);
// sprintf(COT,"U %1.2f",3.41);
SEG_TSL(COT,C0D);
}
(2)计数器初始化
/*
初始化计数器0
*/
void Timer0_Init(void) //100微秒@12MHz
{
AUXR |= 0x80; //定时器时钟1T模式
//计数器模式1
TMOD |= 0x05;
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
PCF8591:
(1)部分主函数:
void Timer1_Isr(void) interrupt 3
{
count_ms++;
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10) key_delay = 0;
if(count_ms == 1000)
{
freq_num = (TH0<<8) | TL0;
count_ms = 0;
TH0 = 0;
TL0 = 0;
}
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Show(l_data);
}
void SEG_Proc()
{
float show_data=0;
if(seg_delay)return;
seg_delay = 1;
show_data = PCF8591_ADC_AIN3();
PCF8591_DAC(show_data);
// sprintf(COT,"F %6u",freq_num);
sprintf(COT,"U %1.2f",show_data/255*5);
SEG_TSL(COT,C0D);
}
(2)PCF8591函数:
#ifndef PCF8591_H
#define PCF8591_H
#include "Public.h"
#include "iic.h"
u8 PCF8591_ADC_AIN3();
void PCF8591_DAC(u8 dac_data);
#endif
#include "PCF8591.h"
u8 PCF8591_ADC_AIN3()
{
u8 dac_data;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
//通道3
IIC_SendByte(0x43);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
dac_data = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return dac_data;
}
void PCF8591_DAC(u8 dac_data)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
//通道3
IIC_SendByte(0x43);
IIC_WaitAck();
IIC_SendByte(dac_data);
IIC_WaitAck();
IIC_Stop();
}
二、实现功能:
基本功能框架:
![](https://i-blog.csdnimg.cn/blog_migrate/23082ad3bc79771b5659291d99551748.png)
数码管可分为三种模式:电压测量模式,频率测量模式,禁用模式。其中电压测量模式分为RB2模式和2V模式
![](https://i-blog.csdnimg.cn/blog_migrate/1116ca02503c86ab59b1dd6f15b08d0c.png)
LED并没特别的要求,不用划分模式,在每次操作后改变一下LED灯就行
参考代码:
(1)主函数:
#include "main.h"
void SEG_Proc();
void Key_Proc();
void Init();
void main()
{
All_Close();
Timer1_Init();
Timer0_Init();
Init();
while(1)
{
Key_Proc();
SEG_Proc();
}
}
void Timer1_Isr(void) interrupt 3
{
count_ms++;
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10) key_delay = 0;
if(count_ms == 1000)
{
freq_num = (TH0<<8) | TL0;
count_ms = 0;
TH0 = 0;
TL0 = 0;
}
SEG_Show(C0D[PSI],PSI);
if(++PSI == 8)PSI = 0;
//L3
if(voli<1.5)
l_data &= ~0x04;
else if(voli<2.5)
l_data |= 0x04;
else if(voli<3.5)
l_data &= ~0x04;
else
l_data |= 0x04;
//L4
if(freq_num<1000)
l_data &= ~0x08;
else if(freq_num<5000)
l_data |= 0x08;
else if(freq_num<10000)
l_data &= ~0x08;
else
l_data |= 0x08;
if(led_turn)
LED_Show(l_data);
else
LED_Show(0x00);
}
void SEG_Proc()
{
float show_data=0;
if(seg_delay)return;
seg_delay = 1;
//电压检测 电压输出
show_data = PCF8591_ADC_AIN3();
voli = show_data/255*5;
if(voli_sub_mode)
PCF8591_DAC(show_data);
else
PCF8591_DAC(2*255/5);
//不同模式下的显示
if(seg_turn)
{
if(seg_mode)
sprintf(COT,"F %6u",freq_num);
else
sprintf(COT,"U %1.2f",voli);
}
else
sprintf(COT," ");
SEG_TSL(COT,C0D);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_down=0;
if(key_delay)return;
key_delay = 1;
key_now = D_Key();
key_down = key_now & (key_now ^ key_old);
key_old = key_now;
switch(key_down)
{
case 4:
seg_mode ^= 1;
l_data = l_data & (~0x03) | (0x01<<seg_mode);
break;
case 5:
voli_sub_mode ^= 1;
l_data ^= 0x10;
break;
case 6:led_turn ^= 1;break;
case 7:seg_turn ^= 1;break;
}
}
void Init()
{
seg_mode = 0;
l_data = l_data & (~0x03) | (0x01<<seg_mode);
seg_turn = 1;
led_turn = 1;
voli_sub_mode = 0;
l_data &= ~0x10;
}
收获:
能加括号尽量加括号,自主定义优先级
计数器只能用模式1(未知问题)
3、只有两种状态切换的时候,定义一个变量取反就行