#include"stc12c5a60s2.h"
#include <intrins.h>
#include<stdio.h>
#define ADC_POWER 0x80
#define ADC_FLAG 0x10
#define ADC_START 0x08
#define CMD_IDLE 0 //IAP等待
#define CMD_READ 1 //读flash
#define CMD_PROGRAM 2 //写入
#define CMD_ERASE 3 //擦除
#define IAP_EN 0x83
#define iap_ADDRESS 0x0000 //地址
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_DATAPINS P0
sfr PCAPWM0 = 0xf2; //定义寄存器PCAPWM0
sfr PCAPWM1 = 0xf3; //定义寄存器PCAPWM1
sbit LCD1602_E=P1^2; //定义lcd1602的使能端
sbit LCD1602_RW=P1^1; //定义lcd1602的写操作端
sbit LCD1602_RS=P1^0; //定义lcd1602的发送命令端
sbit DSPORT=P2^7; //温度传感器读写端
sbit LED0 = P2^3;
sbit LED1 = P2^4;
sbit jia_key=P2^0;//加速按钮
sbit key1 = P2^1; //控制温度调节按键1、2
sbit key2 = P2^2;
sbit key_sw = P3^7;//温控与键控切换开关
uint a=0;
uint b=0;
uint c=0;
uint tem_1=27;
uint tem_2=30;
uchar num=0;
//使硬件或软件操作停止
void iap_IDLE()
{
IAP_CONTR=0; //禁止IAP读写擦除
IAP_CMD=0; //等待
IAP_TRIG=0; //命令未触发
IAP_ADDRH=0x80; //高位数据地址
IAP_ADDRL=0; //低位
}
//从数据里面读取数据
uchar iap_READ(uint addr)
{
uchar datas;
IAP_CONTR=IAP_EN; //控制允许位
IAP_CMD=CMD_READ; //写入读命令
IAP_ADDRL=addr; //自定义地址
IAP_ADDRH=addr>>8;
IAP_TRIG=0x5a; //命令有效
IAP_TRIG=0xa5;
_nop_();
datas=IAP_DATA;
iap_IDLE();
return datas; //返回读出的数据
}
//写一个比特ISP写到某个地方
void iap_PROGRAM(uint addr,uchar datas)
{
IAP_CONTR=IAP_EN;
IAP_CMD=CMD_PROGRAM;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_DATA=datas;
IAP_TRIG=0x5a;
IAP_TRIG=0xa5;
_nop_();
iap_IDLE();
}
//擦掉某个区域
void iap_ERASE(uint addr)
{
IAP_CONTR=IAP_EN;
IAP_CMD=CMD_ERASE;
IAP_ADDRL=addr;
IAP_ADDRH=addr>>8;
IAP_TRIG=0x5a;
IAP_TRIG=0xa5;
_nop_();
iap_IDLE();
}
/******************************************************************************
* 函 数 名 : Delay1ms
* 函数功能 : 延时函数
******************************************************************************/
void Delay1ms(uint y) //粗略延时1ms
{
uint x;
for( ; y>0; y--)
{
for(x=440; x>0; x--);
}
}
void delay1ms(void) //误差 0us
{
unsigned char a,b;
for(b=129;b>0;b--)
for(a=45;a>0;a--);
}
void delay1us(uint x) //误差 0us
{
unsigned char a,b;
for(b=x;b>0;b--)
for(a=3;a>0;a--);
}
/******************************************************************************
* 函 数 名 : Ds18b20Init
* 函数功能 : 初始化
* 输 入 : 无
* 输 出 : 初始化成功返回1,失败返回0
******************************************************************************/
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Delay1ms(5); //保持时间
LCD1602_E = 0;
}
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Delay1ms(1);
LCD1602_E = 1; //写入时序
Delay1ms(5); //保持时间
LCD1602_E = 0;
}
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
uchar Ds18b20Init()
{
uchar i;
DSPORT = 0; //将总线拉低480us~960us
delay1us(642); //延时642us
DSPORT = 1; //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
i = 0;
while(DSPORT) //等待DS18B20拉低总线
{
i++;
if(i>5)//等待>5MS
{
return 0;//初始化失败
}
delay1ms( );
}
return 1;//初始化成功
}
/******************************************************************************
* 函 数 名 : Ds18b20WriteByte
* 函数功能 : 向18B20写入一个字节
******************************************************************************/
void Ds18b20WriteByte(uchar dat)
{
uint j;
for(j=0; j<8; j++)
{
DSPORT = 0; //每写入一位数据之前先把总线拉低1us
delay1us(1);
DSPORT = dat & 0x01; //然后写入一个数据,从最低位开始
delay1us(68); //延时68us,持续时间最少60us
DSPORT = 1; //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
dat >>= 1;
}
}
/*******************************************************************************
* 函 数 名 : Ds18b20ReadByte
* 函数功能 : 读取一个字节
******************************************************************************/
uchar Ds18b20ReadByte()
{
uchar byte, bi;
uint j;
for(j=8; j>0; j--)
{
DSPORT = 0;//先将总线拉低1us
delay1us(1);
DSPORT = 1;//然后释放总线
delay1us(6); //延时6us等待数据稳定
bi = DSPORT; //读取数据,从最低位开始读取
/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
byte = (byte >> 1) | (bi << 7);
delay1us(45);
}
return byte;
}
/*****************************************************************************
* 函 数 名 : Ds18b20ChangTemp
* 函数功能 : 让18b20开始转换温度
******************************************************************************/
void Ds18b20ChangTemp()
{
Ds18b20Init();
delay1ms( );
Ds18b20WriteByte(0xcc); //跳过ROM操作命令
Ds18b20WriteByte(0x44); //温度转换命令
}
/***************************************************************************
* 函 数 名 : Ds18b20ReadTempCom
* 函数功能 : 发送读取温度命令
****************************************************************************/
void Ds18b20ReadTempCom()
{
Ds18b20Init();
delay1ms( );
Ds18b20WriteByte(0xcc); //跳过ROM操作命令
Ds18b20WriteByte(0xbe); //发送读取温度命令
}
/***************************************************************************
* 函 数 名 : Ds18b20ReadTemp
* 函数功能 : 读取温度
****************************************************************************/
int Ds18b20ReadTemp()
{
int temp = 0;
uchar tmh, tml;
Ds18b20ChangTemp(); //先写入转换命令
Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令
tml = Ds18b20ReadByte(); //读取温度值共16位,先读低字节
tmh = Ds18b20ReadByte(); //再读高字节
temp = tmh;
temp <<= 8;
temp |= tml;
return temp;
}
/*****************************************************************************
* 函数名 : LcdDisplay()
* 函数功能 : LCD显示读取到的温度
*****************************************************************************/
void LcdDisplay(int temp) //lcd显示
{
unsigned char datas[] = {0, 0, 0, 0, 0}; //定义数组
float tp;
if(temp< 0) //当温度值为负数
{
LcdWriteCom(0x80); //写地址 80表示初始地址
LcdWriteData('-'); //显示负
//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
temp=temp-1;
temp=~temp;
tp=temp;
temp=tp*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。
}
else
{
LcdWriteCom(0x80); //写地址 80表示初始地址
LcdWriteData('+'); //显示正
tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
//如果温度是正的那么,那么正数的原码就是补码它本身
temp=tp*0.0625*100+0.5;
//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
//算加上0.5,还是在小数点后面。
}
datas[0] = temp / 10000;
datas[1] = temp % 10000 / 1000;
datas[2] = temp % 1000 / 100;
datas[3] = temp % 100 / 10;
datas[4] = temp % 10;
a = datas[0]; //a,b,c的作用是取温度的整数,进行温控
b = datas[1];
c = datas[2];
LcdWriteCom(0x82); //写地址
LcdWriteData('0'+datas[0]); //百位
LcdWriteCom(0x83); //写地址
LcdWriteData('0'+datas[1]); //十位
LcdWriteCom(0x84); //写地址
LcdWriteData('0'+datas[2]); //个位
LcdWriteCom(0x85); //写地址
LcdWriteData('.'); //显示 '.'
LcdWriteCom(0x86); //写地址
LcdWriteData('0'+datas[3]); //显示小数点
LcdWriteCom(0x87); //写地址
LcdWriteData('0'+datas[4]); //显示小数
}
/*********************************************
温度控制电机输出占空比函数
***********************************************/
void control (void)
{
if((a*100+b*10+c)< tem_1)
{
CCAP0H = CCAP0L = 0xff; //PWM0 口输出 0%占空比
LED0 = 0;
LED1 = 0;
}
else if (tem_1 <= (a*100+b*10+c)&&(a*100+b*10+c)<tem_2 )
{
CCAP0H = CCAP0L = 0xB3; //PWM0 口输出30%占空比
LED0 = 1;
LED1 = 0;
}
else if (tem_2 <= (a*100+b*10+c))
{
CCAP0H = CCAP0L = 0x1a; //PWM0 口输出90%占空比
LED0 = 1;
LED1 = 1;
}
}
/******************************************************************************
* 函数名 : keyscan
* 函数功能 : 键盘扫描
******************************************************************************/
void keyscan1 ()
{
if (0 == key1) //温度下限调整按键
{
Delay1ms(20);
if (0 == key1)
{
tem_1++;
if(31 == tem_1)
tem_1 = 17;
while(!key1);
}
}
if (0 == key2) //温度上限调整按键
{
Delay1ms(20);
if (0 == key2)
{
tem_2++;
if(44 == tem_2)
tem_2 = 23;
while(!key2 );
}
}
if(tem_1 == tem_2) tem_2++; //防止两个温度范围一样
if(tem_2 < tem_1) //防止温度上限比温度下限低
{
tem_2=tem_1+1;
}
}
void keyscan2 ()
{
if(jia_key==0) //加速按键
{
Delay1ms(20);;
if(jia_key==0)
{
num++;
if(num==3)
num=0;
while(jia_key==0);
}
}
}
/*********************************************
电机输出档位选择函数
***********************************************/
void dangwei()
{
switch(num)
{
case 0:
CCAP0H = CCAP0L = 0xff; //PWM0 口输出 0%占空比
LED0 = 0;
LED1 = 0;
break;
case 1:
CCAP0H = CCAP0L = 0x67; //PWM0 口输出60%占空比
LED0 = 1;
LED1 = 0;
break;
case 2:
CCAP0H = CCAP0L = 0x1a; //PWM0 口输出90%占空比
LED0 = 1;
LED1 = 1;
break;
}
}
/****************************************************************************
* 函数名 : displayx ()
* 函数功能 : LCD显示读取到的键盘的数值
*****************************************************************************/
void display1 (int p)
{
unsigned char datas[] = {0, 0};
datas[0] = p / 10;
datas[1] = p % 10;
LcdWriteCom(0x8b);
LcdWriteData('0'+datas[0]);
LcdWriteCom(0x8c);
LcdWriteData('0'+datas[1]);
}
void display2 (int t)
{
unsigned char datas[] = {0, 0};
datas[0] = t / 10;
datas[1] = t % 10;
LcdWriteCom(0x8e);
LcdWriteData('0'+datas[0]);
LcdWriteCom(0x8f);
LcdWriteData('0'+datas[1]);
}
/*********************************************
电机输出寄存器初始化函数
***********************************************/
void init_dianji()
{
CCON = 0; //初始化 PCA控制寄存器
//PCA计数器停止运行
//清除CF标志位
//清除所有中断标志位
CL = 0; //重置PCA的16位计数器
CH = 0;
CMOD = 0x02; //设置 PCA 计数器时钟源为 Fosc/2
//禁止PCA 计数器溢出中断
CCAPM0 = 0x42; //PCA模块0工作在8位PWM模式并且没有PCA中断
CR = 1; //PCA 计数器开始运行
}
/****************************************************************************
* 函数名 : main
* 函数功能 : 主函数
*****************************************************************************/
void main()
{
LED0=0;
LED1=0;
CCAP0H = CCAP0L = 0xff;
P1M1 = 0x00;
P1M0 = 0x08; //把P1.3口定义为强推挽输出,驱动电机
P2M1 = 0x00;
P2M0 = 0x18; //把P2.3和P2.4定义为强推挽输出,驱动LED
LcdInit(); //初始化LCD1602
init_dianji(); //电机PWM驱动初始化
while(1)
{
if(1 == key_sw) //温控模式
{
LcdWriteCom(0x88); //写地址 88
LcdWriteData('C');
LcdDisplay(Ds18b20ReadTemp()); //温度读取显示
control (); //温度控制电机占空比
keyscan1 (); //键盘扫描
display1 (tem_1); //控制温度数字显示
display2 (tem_2);
}
if(0 == key_sw) //键控模式
{
LcdWriteCom(0xc2);
LcdWriteData('D');
LcdWriteCom(0xc3);
LcdWriteData('W');
LcdWriteCom(0xc4);
LcdWriteData(':');
dangwei(); //键控电机档位选择
keyscan2 (); //键盘扫描
LcdWriteCom(0xc5);
LcdWriteData('0'+num); //显示按键档位
}
}
}
|