一、初始化外设:
![](https://i-blog.csdnimg.cn/blog_migrate/4cd689b3d6d6666d4100934f6ff73311.png)
新建工程:
(1)主函数:
#ifndef MAIN_H
#define MAIN_H
#include "Public.h"
#endif
#include "main.h"
void main()
{
All_Close();
}
(2)公共函数:
#ifndef Public_H
#define Public_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Select(u8 cs,u8 s_data);
void All_Close();
#endif
#include "Public.h"
/*
选择锁存器,传输数据
*/
void Select(u8 cs,u8 s_data)
{
P0 = s_data;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void All_Close()
{
//关闭蜂鸣器和继电器
Select(5,0x00);
//关闭LED
Select(4,0xff);
//将数码管段选清除
Select(7,0xff);
}
数码管显示:
(1)主函数:
#include "main.h"
void SEG_Proc();
void main()
{
All_Close();
Timer1_Init();
while(1)
{
SEG_Proc();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PSI],PSI);
if(++PSI == 8)PSI = 0;
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
// sprintf(COT,"C %2.2f",temper);
// sprintf(COT,"P %2u",(u16)set_temper);
volt = 3.25;
sprintf(COT,"A %1.2f",volt);
SEG_TSL(COT,COD);
}
(2)数码管:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *input,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 'C':output[i] = Seg_Table[12];break;
case 'A':output[i] = Seg_Table[10];break;
case 'P':output[i] = ~0x73;break;
default:output[i] = 0xff;
}
if(input[j+1] == '.')
{
output[i] &= ~0x80;
j++;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消隐
Select(7,0xff);
//位选
Select(6,0x01<<PSI);
//段选
Select(7,COD);
}
(3)定时器:
#ifndef SIMPLE_H
#define SIMPLE_H
#include "Public.h"
void Timer1_Init(void);
#endif
#include "Simple.h"
void Timer1_Init(void) //1毫秒@12MHz
{
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)
{
// SEG_Proc();
Key_Proc();
}
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon)
{
sprintf(COT,"%u",(u16)key_dwon);
SEG_TSL(COT,COD);
}
}
(2)按键检测:
/*
矩阵按键按键检测
*/
u8 M_Key()
{
u8 i=0;
u16 key_temp=0;
P44=0;P42=1;P35=1;P34=1;
key_temp |= (P3 & 0x0f);
P44=1;P42=0;P35=1;P34=1;
key_temp = (key_temp<<4) | (P3 & 0x0f);
P44=1;P42=1;P35=0;P34=1;
key_temp = (key_temp<<4) | (P3 & 0x0f);
P44=1;P42=1;P35=1;P34=0;
key_temp = (key_temp<<4) | (P3 & 0x0f);
for(i=0;i<16;i++)
{
if((key_temp & (0x8000>>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(COD[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Show(l_data);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon)
{
l_data = 0x01<<(key_dwon-4);
}
}
(2)LED显示:
/*
输入8位数显示对应的LED,1为亮灯
*/
void LED_Show(u8 l_data)
{
Select(4,~l_data);
}
DS18B20:
(1)部分主函数:
void main()
{
All_Close();
Timer1_Init();
while(1)
{
SEG_Proc();
// Key_Proc();
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
temper = DS18B20_Read()/16.0;
sprintf(COT,"C %2.2f",temper);
// sprintf(COT,"P %2u",(u16)set_temper);
// volt = 3.25;
// sprintf(COT,"A %1.2f",volt);
SEG_TSL(COT,COD);
}
(2)DS18B20:
/*
温度读取
*/
u16 DS18B20_Read()
{
u8 LSB,MSB;
//转换温度
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
//读取温度
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
return LSB | (MSB<<8);
}
PCF8591:
(1)部分主函数:
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
// temper = DS18B20_Read()/16.0;
// sprintf(COT,"C %2.2f",temper);
volt = 4.241;
sprintf(COT,"A %1.2f",volt);
SEG_TSL(COT,COD);
//改变输出电压
PCF8591_DAC(volt);
}
(2)PCF8591:
/*
输出电压
*/
void PCF8591_DAC(float volt)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte((u8)(volt*255/5));
IIC_WaitAck();
IIC_Stop();
}
二、实现功能:
基本框架:
![](https://i-blog.csdnimg.cn/blog_migrate/73df5382418e4d2e7e41eef6571ff566.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6b3b637a9583fcb591a2897a2a8bc47e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6477e5f813808ead631b2e768f2ff0b7.png)
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//温度采集
temper = DS18B20_Read()/16.0;
switch(seg_mode)
{
case Temper_Mode:sprintf(COT,"C %2.2f",temper);break;
case Set_Mode:sprintf(COT,"P %2u",(u16)set_temper);break;
case DAC_Mode:sprintf(COT,"A %1.2f",volt);break;
}
SEG_TSL(COT,COD);
//改变输出电压
PCF8591_DAC(volt);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 4)
{
if(++seg_mode == 3)seg_mode = 0;
if(seg_mode == DAC_Mode);
}
else if(seg_mode == Set_Mode)
{
if(key_dwon == 8)
{
}
else if(key_dwon == 9)
{
}
}
else if(key_dwon == 5)
{
dac_set_mode ^= 1;
}
}
void Init()
{
seg_mode = Temper_Mode;
dac_set_mode = 0;
set_temper = 25;
}
设置模式:
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//温度采集
temper = DS18B20_Read()/16.0;
switch(seg_mode)
{
case Temper_Mode:sprintf(COT,"C %2.2f",temper);break;
case Set_Mode:sprintf(COT,"P %2u",(u16)set_temp);break;
case DAC_Mode:sprintf(COT,"A %1.2f",volt);break;
}
SEG_TSL(COT,COD);
//改变输出电压
PCF8591_DAC(volt);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 4)
{
if(++seg_mode == 3)seg_mode = 0;
if(seg_mode == Set_Mode)
set_temp = set_temper;
if(seg_mode == DAC_Mode);
set_temper = set_temp;
}
else if(seg_mode == Set_Mode)
{
if(key_dwon == 8)
{
if(--set_temp==255)set_temp = 99;
}
else if(key_dwon == 9)
{
if(++set_temp==100)set_temp = 0;
}
}
else if(key_dwon == 5)
{
dac_set_mode ^= 1;
}
}
DAC模式:
![](https://i-blog.csdnimg.cn/blog_migrate/840718136d89e33ce8457eb22794b62c.png)
(1)部分主函数:
void main()
{
All_Close();
Timer1_Init();
Init();
while(1)
{
SEG_Proc();
Key_Proc();
}
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//温度采集
temper = DS18B20_Read()/16.0;
//改变输出电压
if(dac_set_mode)
{
if(temper<=20)
volt = 1;
else if(temper<40)//3/20 = (volt-1)/(temper-20)
volt = (temper-20)*(3.0/20) + 1;
else
volt = 4;
}
else
{
if(temper<set_temper)
volt = 0;
else
volt = 5;
}
PCF8591_DAC(volt);
switch(seg_mode)
{
case Temper_Mode:sprintf(COT,"C %2.2f",temper);break;
case Set_Mode:sprintf(COT,"P %2u",(u16)set_temp);break;
case DAC_Mode:sprintf(COT,"A %1.2f",volt);break;
}
SEG_TSL(COT,COD);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 4)
{
if(++seg_mode == 3)seg_mode = 0;
if(seg_mode == Set_Mode)
set_temp = set_temper;
if(seg_mode == DAC_Mode);
set_temper = set_temp;
l_data = l_data & 0xf1 | (0x02<<seg_mode);
}
else if(seg_mode == Set_Mode)
{
if(key_dwon == 8)
{
if(--set_temp==255)set_temp = 99;
}
else if(key_dwon == 9)
{
if(++set_temp==100)set_temp = 0;
}
}
else if(key_dwon == 5)
{
dac_set_mode ^= 1;
l_data ^= 0x01;
}
}
void Init()
{
seg_mode = Temper_Mode;
dac_set_mode = 0;
set_temper = 25;
l_data = 0x01 | 0x02;
}
三、参考代码:
主函数
#ifndef MAIN_H
#define MAIN_H
#include "Public.h"
#include "stdio.h"
#include "SEG.h"
#include "Simple.h"
//数码管模式
u8 seg_mode;
#define Temper_Mode 0
#define Set_Mode 1
#define DAC_Mode 2
//DAC模式
u8 dac_set_mode;
//定时器
u16 seg_delay;
u8 key_delay;
//数码管显示
float temper,volt;
u8 set_temper,set_temp;
u8 COT[10],COD[8],PSI;
//LED
u8 l_data;
#endif
#include "main.h"
void SEG_Proc();
void Key_Proc();
void Init();
void main()
{
All_Close();
Timer1_Init();
Init();
while(1)
{
SEG_Proc();
Key_Proc();
}
}
void Timer1_Isr(void) interrupt 3
{
if(++seg_delay == 500)seg_delay = 0;
if(++key_delay == 10)key_delay = 0;
SEG_Show(COD[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Show(l_data);
}
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
//温度采集
temper = DS18B20_Read()/16.0;
//改变输出电压
if(dac_set_mode)
{
if(temper<=20)
volt = 1;
else if(temper<40)//3/20 = (volt-1)/(temper-20)
volt = (temper-20)*(3.0/20) + 1;
else
volt = 4;
}
else
{
if(temper<set_temper)
volt = 0;
else
volt = 5;
}
PCF8591_DAC(volt);
switch(seg_mode)
{
case Temper_Mode:sprintf(COT,"C %2.2f",temper);break;
case Set_Mode:sprintf(COT,"P %2u",(u16)set_temp);break;
case DAC_Mode:sprintf(COT,"A %1.2f",volt);break;
}
SEG_TSL(COT,COD);
}
void Key_Proc()
{
static u8 key_old;
u8 key_now=0,key_dwon=0;
if(key_delay)return;
key_delay = 1;
key_now = M_Key();
key_dwon = key_now & (key_now ^ key_old);
key_old = key_now;
if(key_dwon == 4)
{
if(++seg_mode == 3)seg_mode = 0;
if(seg_mode == Set_Mode)
set_temp = set_temper;
if(seg_mode == DAC_Mode);
set_temper = set_temp;
l_data = l_data & 0xf1 | (0x02<<seg_mode);
}
else if(seg_mode == Set_Mode)
{
if(key_dwon == 8)
{
if(--set_temp==255)set_temp = 99;
}
else if(key_dwon == 9)
{
if(++set_temp==100)set_temp = 0;
}
}
else if(key_dwon == 5)
{
dac_set_mode ^= 1;
l_data ^= 0x01;
}
}
void Init()
{
seg_mode = Temper_Mode;
dac_set_mode = 0;
set_temper = 25;
l_data = 0x01 | 0x02;
}
公共函数:
#ifndef Public_H
#define Public_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void Select(u8 cs,u8 s_data);
void All_Close();
#endif
#include "Public.h"
/*
选择锁存器,传输数据
*/
void Select(u8 cs,u8 s_data)
{
P0 = s_data;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void All_Close()
{
//关闭蜂鸣器和继电器
Select(5,0x00);
//关闭LED
Select(4,0xff);
//将数码管段选清除
Select(7,0xff);
}
数码管:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *input,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 'C':output[i] = Seg_Table[12];break;
case 'A':output[i] = Seg_Table[10];break;
case 'P':output[i] = ~0x73;break;
default:output[i] = 0xff;
}
if(input[j+1] == '.')
{
output[i] &= ~0x80;
j++;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消隐
Select(7,0xff);
//位选
Select(6,0x01<<PSI);
//段选
Select(7,COD);
}
外设:
#ifndef SIMPLE_H
#define SIMPLE_H
#include "Public.h"
#include "onewire.h"
#include "iic.h"
void Timer1_Init(void);
u8 M_Key();
void LED_Show(u8 l_data);
u16 DS18B20_Read();
void PCF8591_DAC(float volt);
#endif
#include "Simple.h"
void Timer1_Init(void) //1毫秒@12MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
EA = 1;
}
/*
矩阵按键按键检测
*/
u8 M_Key()
{
u8 i=0;
u16 key_temp=0;
P44=0;P42=1;P35=1;P34=1;
key_temp |= (P3 & 0x0f);
P44=1;P42=0;P35=1;P34=1;
key_temp = (key_temp<<4) | (P3 & 0x0f);
P44=1;P42=1;P35=0;P34=1;
key_temp = (key_temp<<4) | (P3 & 0x0f);
P44=1;P42=1;P35=1;P34=0;
key_temp = (key_temp<<4) | (P3 & 0x0f);
for(i=0;i<16;i++)
{
if((key_temp & (0x8000>>i)) == 0)
return i+4;
}
return 0;
}
/*
输入8位数显示对应的LED,1为亮灯
*/
void LED_Show(u8 l_data)
{
Select(4,~l_data);
}
/*
温度读取
*/
u16 DS18B20_Read()
{
u8 LSB,MSB;
//转换温度
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
//读取温度
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
return LSB | (MSB<<8);
}
/*
输出电压
*/
void PCF8591_DAC(float volt)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte((u8)(volt*255/5));
IIC_WaitAck();
IIC_Stop();
}
四、 收获:
数码管是输入0亮
判断某位,建议用“==”判断
![](https://i-blog.csdnimg.cn/blog_migrate/3f20118754ad99e0e9cc750d7f497b43.png)
3、注意使用矩阵按键时不能用计数器0采集,因为和按键的P34口重复了
4、float型强制转换成unsinged char 会保留8位整数位