************* 本程序功能说明 **************
本例程基于STC8H8K64U为主控芯片的开天斧3开发板,由实验箱等程序修改而来,STC8H系列带RTC模块的芯片可通用参考.
读写芯片内部集成的RTC模块. 板子上无记忆电池需持续供电,使用板载NTC获取周围温度。
读接在ADC口的NTC,测温度,用STC的MCU的SPI口模拟SPI时序驱动OLED128x64。
使用Timer0的16位自动重装来产生1ms节拍, 程序运行于这个节拍下, 用户修改MCU主时钟频率时,自动定时于1ms.
OLED显示日期时间(年月日 小时:分钟:秒), 显示温度(- 00.0℃),分辨率0.1度。NTC使用1%精度的MF52 10K@25度.
测温度时使用12位ADC值, 使用对分查找表格来计算, 小数点后一位数是线性插补的. 如需提高精度可以参考开天斧的ADC过采样。
4个独立按键键码为2~5.
按键用于调节时间, 只支持单键按下, 不支持多键同时按下.
键按下超过1秒后,将以10键/秒的速度提供长按的输出. 用户只需要检测KeyCode是否非0来判断键是否按下.
调整时间键:
键码5: 小时+. P3.5
键码4: 小时-. P3.4
键码3: 分钟+. P3.3
键码2: 分钟-. P3.2
下载时, 选择时钟 24MHZ (用户可自行修改频率).
******************************************/
#include "STC8H.h" //包含本头文件后,不用另外再包含"REG51.H"
#include "intrins.h"
#include "stdio.h"
#include "oledfont.h"
#include "bmp.h"
#define MAIN_Fosc 24000000L //定义主时钟
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//开天斧oled接口定义
sbit OLED_D0 =P2^5;//SCL,D0,SCLK
sbit OLED_D1 =P2^3;//SDA,D1,MOSI
sbit OLED_RES =P2^0;//RES
sbit OLED_DC =P2^1;//DC
sbit OLED_CS =P2^2; //CS
#define KEYport P3 //P3.2-P3.5
/***********************************************************/
/****************************** 用户定义宏 ***********************************/
#define PrintUart 2 //1:printf 使用 UART1; 2:printf 使用 UART2
#define Baudrate 115200L //串口波特率
#define TM (65536 -(MAIN_Fosc/Baudrate/4))
#define Timer0_Reload (65536UL -(MAIN_Fosc / 1000)) //Timer 0 中断频率, 1000次/秒
#define SleepModeSet 0 //0:不进休眠模式,使用屏幕显示时不能进休眠; 1:使能休眠模式
#define OLED_CMD 0 //OLED写命令
#define OLED_DATA 1 //OLED写数据
//-----------------OLED端口定义----------------
#define OLED_D0_Clr() OLED_D0=0
#define OLED_D0_Set() OLED_D0=1
#define OLED_D1_Clr() OLED_D1=0
#define OLED_D1_Set() OLED_D1=1
#define OLED_RES_Clr() OLED_RES=0
#define OLED_RES_Set() OLED_RES=1
#define OLED_DC_Clr() OLED_DC=0
#define OLED_DC_Set() OLED_DC=1
#define OLED_CS_Clr() OLED_CS=0
#define OLED_CS_Set() OLED_CS=1
/*****************************************************************************/
/************* 本地常量声明 **************/
/************* 本地变量声明 **************/
u8 LED8[8]; //显示缓冲
bit B_1ms; //1ms标志
bit B_1s;
bit B_Alarm; //闹钟标志
u8 IO_KeyState, IO_KeyState1, IO_KeyHoldCnt; //键盘变量
u8 KeyHoldCnt; //键按下计时
u8 KeyCode; //给用户使用的键码
u8 cnt50ms;
u8 hour,minute; //RTC变量
/************* 本地函数声明 **************/
void IO_KeyScan(void); //50ms call
void WriteRTC(void);
void RTC_config(void);
//OLED用函数
void OLEDDisplayRTC(void);
void delay_ms(unsigned int ms);
void OLED_ColorTurn(u8 i);
void OLED_DisplayTurn(u8 i);
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Set_Pos(u8 x, u8 y);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Clear(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey);
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey);
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]);
void OLED_Init(void);
//OLED
//ADC,NTC
u16 get_temperature(u16 adc);
u16 Get_ADC12bitResult(u8 channel); //channel = 0~15. chn=0~7对应P1.0~P1.7, chn=8~14对应P0.0~P0.6, chn=15对应BandGap电压
//ADC,NTC
/******************** 串口打印函数 ********************/
void UartInit(void)
{
#if(PrintUart == 1)
SCON = (SCON & 0x3f) | 0x40;
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TL1 = TM;
TH1 = TM>>8;
TR1 = 1; //定时器1开始计时
// REN = 1; //允许接收
// SCON = (SCON & 0x3f) | 0x40;
// T2L = TM;
// T2H = TM>>8;
// AUXR |= 0x15; //串口1选择定时器2为波特率发生器
// REN = 1; //允许接收
#else
P_SW2 |= 1; //UART2 switch to: 0: P1.0 P1.1, 1: P4.6 P4.7
S2CON &= ~(1<<7); //8位数据, 1位起始位, 1位停止位, 无校验
T2L = TM;
T2H = TM>>8;
AUXR |= 0x14; //定时器2时钟1T模式,开始计时
// S2CON |= (1<<4); //允许接收
#endif
}
void UartPutc(unsigned char dat)
{
#if(PrintUart == 1)
SBUF = dat;
while(TI==0);
TI = 0;
#else
S2BUF = dat;
while((S2CON & 2) == 0);
S2CON &= ~2; //Clear Tx flag
#endif
}
char putchar(char c)
{
UartPutc(c);
return c;
}
/**********************************************/
void main(void)
{
u8 i;
u16 j;
//设置IO模式
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
AUXR = 0x80; //Timer0 set as 1T, 16 bits timer auto-reload,
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
ET0 = 1; //Timer0 interrupt enable
TR0 = 1; //Tiner0 run
UartInit();
RTC_config();
EA = 1; //打开总中断
KeyHoldCnt = 0; //键按下计时
KeyCode = 0; //给用户使用的键码
IO_KeyState = 0;
IO_KeyState1 = 0;
IO_KeyHoldCnt = 0;
cnt50ms = 0;
OLED_Init();//初始化OLED
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
OLED_DrawBMP(0,0,128,64,BMP1);
delay_ms(1000);
OLED_Clear();
P_SW2 |= 0x80; //使能XFR访问, 准备读RTC
OLED_ShowString(0,2,"20",16);
OLED_ShowNum(18,2,YEAR,2,16);
OLED_ShowChinese(36,2,0,16);//年
OLED_ShowNum(54,2,MONTH,2,16);
OLED_ShowChinese(72,2,1,16);//月
OLED_ShowNum(90,2,DAY,2,16);
OLED_ShowChinese(108,2,2,16);//日
OLEDDisplayRTC();
P_SW2 |= 0x80; //使能XFR访问
ADCTIM = 0x3f; //设置 ADC 内部时序,ADC采样时间建议设最大值
P_SW2 &= 0x7f;
ADCCFG = 0x2f; //设置 ADC 时钟为系统时钟/2/16/16
ADC_CONTR = 0x80; //使能 ADC 模块
while(1)
{
if(B_1s) //1S到
{
B_1s = 0;
P_SW2 |= 0x80; //使能XFR访问
OLEDDisplayRTC();
printf("Year=20%bd,Month=%bd,Day=%bd,Hour=%bd,Minute=%bd,Second=%bd\r\n",YEAR,MONTH,DAY,HOUR,MIN,SEC);
//P_SW2 &= ~0x80; //禁止XFR访问
j = Get_ADC12bitResult(3); //参数0~15,查询方式做一次ADC, 返回值就是结果, == 4096 为错误
if(j < 4096)
{
j = get_temperature(j); //计算温度值
if(j >= 400) F0 = 0, j -= 400; //温度 >= 0度
else F0 = 1, j = 400 - j; //温度 < 0度
LED8[4] = j / 1000; //显示温度值, 百位
LED8[5] = (j % 1000) / 100; //十位
LED8[6] = (j % 100) / 10 ; //个位
LED8[7] = j % 10; //小数
if(F0) OLED_ShowChar(28,6,'-',16); //显示-
else OLED_ShowChar(28,6,' ',16);
if(LED8[4] == 0) OLED_ShowChar(36,6,' ',16);
else OLED_ShowNum(36,6,LED8[4],1,16);
OLED_ShowNum(45,6,LED8[5],1,16);
OLED_ShowNum(54,6,LED8[6],1,16);
OLED_ShowChar(63,6,'.',16);
OLED_ShowNum(72,6,LED8[7],1,16);
OLED_ShowChinese(81,6,9,16);//℃
;
}
else //错误
{
OLED_ShowString(28,6,"ERROR",16);
}
}
if(B_Alarm)
{
B_Alarm = 0;
printf("RTC Alarm!\r\n");
OLEDDisplayRTC();
OLED_ShowString(45,0,"Alarm!",16);
}
#if(SleepModeSet == 1)
_nop_();
_nop_();
PCON = 0x02; //STC8H8K64U B版本芯片使用内部32K时钟,休眠无法唤醒
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
#else
if(B_1ms) //1ms到
{
B_1ms = 0;
if(++cnt50ms >= 50) //50ms扫描一次键盘
{
cnt50ms = 0;
IO_KeyScan();
}
if(KeyCode != 0) //有键按下, 调时间
{
if(KeyCode == 5) //hour +1
{
if(++hour >= 24) hour = 0;
WriteRTC();
}
if(KeyCode == 4) //hour -1
{
if(--hour >= 24) hour = 23;
WriteRTC();
}
if(KeyCode == 3) //minute +1
{
if(++minute >= 60) minute = 0;
WriteRTC();
}
if(KeyCode == 2) //minute -1
{
if(--minute >= 60) minute = 59;
WriteRTC();
}
KeyCode = 0;
OLEDDisplayRTC();
OLED_ShowString(45,0," ",16); //去掉闹钟显示
}
}
#endif
}
}
/********************** 写RTC函数 ************************/
void WriteRTC(void)
{
P_SW2 |= 0x80; //使能XFR访问
INIYEAR = YEAR; //继承当前年月日
INIMONTH = MONTH;
INIDAY = DAY;
INIHOUR = hour; //修改时分秒
INIMIN = minute;
INISEC = 0;
INISSEC = 0;
RTCCFG |= 0x01; //触发RTC寄存器初始化
P_SW2 &= ~0x80; //禁止XFR访问
}
u8 code T_KeyTable[9] = {0,2,3,0,4,0,0,0,5};
void IO_KeyScan(void) //独立按键扫描与识别. 50ms调用, 支持单键连续按下, 不支持多键同时按下
{
u8 j;
j = IO_KeyState1; //保存上一次状态
KEYport = 0xff;
IO_KeyState1 = KEYport & 0x3C;
IO_KeyState1 ^= 0xff; //取反
IO_KeyState1=(IO_KeyState1 & 0x3C) >> 2;
if(j == IO_KeyState1) //连续两次读相等
{
j = IO_KeyState;
IO_KeyState = IO_KeyState1;
if(IO_KeyState != 0) //有键按下
{
F0 = 0;
if(j == 0) F0 = 1; //第一次按下
else if(j == IO_KeyState)
{
if(++IO_KeyHoldCnt >= 20) //1秒后长按
{
IO_KeyHoldCnt = 18;
F0 = 1;
}
}
if(F0)
{
KeyCode =T_KeyTable[IO_KeyState]; //计算键码,2~5
}
}
else IO_KeyHoldCnt = 0;
}
KEYport = 0xff;
}
/******************** RTC中断函数 *********************/
void RTC_Isr() interrupt 13 //借用保留中断号使用RTC中断
{
char store;
store = P_SW2;
P_SW2 |= 0x80;
if(RTCIF & 0x80) //闹钟中断
{
P01 = !P01;
RTCIF &= ~0x80;
B_Alarm = 1;
}
if(RTCIF & 0x08) //秒中断
{
P00 = !P00;
RTCIF &= ~0x08;
B_1s = 1;
}
P_SW2 = store;
}
/********************** Timer0 1ms中断函数 ************************/
void timer0 (void) interrupt 1
{
#if(SleepModeSet == 0)
//
#endif
B_1ms = 1; //1ms标志
}
//========================================================================
// 函数: void RTC_config(void)
// 描述: RTC初始化函数。
// 参数: 无.
// 返回: 无.
// 版本: V1.0, 2020-6-10
//========================================================================
void RTC_config(void)
{
P_SW2 |= 0x80; //使能XFR访问
INIYEAR = 23; //Y:2023
INIMONTH = 5; //M: 5
INIDAY = 1; //D: 1
INIHOUR = 23; //H:23
INIMIN = 59; //M:59
INISEC = 50; //S:50
INISSEC = 0; //S/128:0
ALAHOUR = 0; //闹钟小时
ALAMIN = 0; //闹钟分钟
ALASEC = 0; //闹钟秒
ALASSEC = 0; //闹钟1/128秒
//STC8H8K64U B版本芯片使用内部32K时钟,休眠无法唤醒
IRC32KCR = 0x80; //启动内部32K晶振.
while (!(IRC32KCR & 1)); //等待时钟稳定
RTCCFG = 0x03; //选择内部32K时钟源,触发RTC寄存器初始化
// X32KCR = 0x80 + 0x40; //启动外部32K晶振, 低增益+0x00, 高增益+0x40.
// while (!(X32KCR & 1)); //等待时钟稳定
// RTCCFG = 0x01; //选择外部32K时钟源,触发RTC寄存器初始化
RTCIF = 0x00; //清中断标志
RTCIEN = 0x88; //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断, 0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断, 0x02:1/8秒中断, 0x01:1/32秒中断
RTCCR = 0x01; //RTC使能
while(RTCCFG & 0x01); //等待初始化完成,需要在 "RTC使能" 之后判断.
//设置RTC时间需要32768Hz的1个周期时间,大约30.5us. 由于同步, 所以实际等待时间是0~30.5us.
//如果不等待设置完成就睡眠, 则RTC会由于设置没完成, 停止计数, 唤醒后才继续完成设置并继续计数.
P_SW2 &= ~0x80; //禁止XFR访问
}
//OLED的显存存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
/********************** 显示时钟函数 ************************/
void OLEDDisplayRTC(void)
{
P_SW2 |= 0x80; //使能XFR访问, 准备读RTC
OLED_ShowNum(27,4,HOUR,2,16);
OLED_ShowChar(45,4,':',16);
OLED_ShowNum(54,4,(MIN / 10),1,16);
OLED_ShowNum(63,4,(MIN % 10),1,16);
OLED_ShowChar(72,4,':',16);
OLED_ShowNum(81,4,(SEC / 10),1,16);
OLED_ShowNum(90,4,(SEC % 10),1,16);
if(HOUR == 0 && MIN == 0)
{
OLED_ShowString(0,2,"20",16);
OLED_ShowNum(18,2,YEAR,2,16);
OLED_ShowChinese(36,2,0,16);//年
OLED_ShowNum(54,2,MONTH,2,16);
OLED_ShowChinese(72,2,1,16);//月
OLED_ShowNum(90,2,DAY,2,16);
OLED_ShowChinese(108,2,2,16);//日
}
P_SW2 &= ~0x80; //禁止XFR访问
}
void delay_ms(unsigned int ms)
{
unsigned int a;
while(ms)
{
a=1800;
while(a--);
ms--;
}
return;
}
//反显函数
void OLED_ColorTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
}
if(i==1)
{
OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
}
}
//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
OLED_WR_Byte(0xA1,OLED_CMD);
}
if(i==1)
{
OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
OLED_WR_Byte(0xA0,OLED_CMD);
}
}
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
for(i=0;i<8;i++)
{
OLED_D0_Clr();
if(dat&0x80)
{
OLED_D1_Set();
}
else
{
OLED_D1_Clr();
}
OLED_D0_Set();
dat<<=1;
}
OLED_CS_Set();
OLED_DC_Set();
}
//坐标设置
void OLED_Set_Pos(u8 x, u8 y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//sizey:选择字体 6x8 8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey)
{
u8 c=0,sizex=sizey/2;
u16 i=0,size1;
if(sizey==8)size1=6;
else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
c=chr-' ';//得到偏移后的值
OLED_Set_Pos(x,y);
for(i=0;i<size1;i++)
{
if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号
else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号
// else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
{
u8 t,temp,m=0;
u8 enshow=0;
if(sizey==8)m=2;
for(t=0;t<len;t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey)
{
u8 j=0;
while (chr[j]!='\0')
{
OLED_ShowChar(x,y,chr[j++],sizey);
if(sizey==8)x+=6;
else x+=sizey/2;
}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)
{
u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
for(i=0;i<size1;i++)
{
if(i%sizey==0) OLED_Set_Pos(x,y++);
if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号
// else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[])
{
u16 j=0;
u8 i,m;
sizey=sizey/8+((sizey%8)?1:0);
for(i=0;i<sizey;i++)
{
OLED_Set_Pos(x,i+y);
for(m=0;m<sizex;m++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
//初始化
void OLED_Init(void)
{
OLED_RES_Clr();
delay_ms(200);
OLED_RES_Set();
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_Clear();
OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}
//========================================================================
// 函数: u16 Get_ADC12bitResult(u8 channel)
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC.
// 返回: 12位ADC结果.
// 版本: V1.0, 2012-10-22
//========================================================================
u16 Get_ADC12bitResult(u8 channel) //channel = 0~15
{
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel; //启动 AD 转换
_nop_();
_nop_();
_nop_();
_nop_();
while((ADC_CONTR & 0x20) == 0) ; //wait for ADC finish
ADC_CONTR &= ~0x20; //清除ADC结束标志
return (((u16)ADC_RES << 8) | ADC_RESL);
}
// MF52E 10K at 25, B = 3950, ADC = 12 bits
u16 code temp_table[]={
140, //;-40 0
149, //;-39 1
159, //;-38 2
168, //;-37 3
178, //;-36 4
188, //;-35 5
199, //;-34 6
210, //;-33 7
222, //;-32 8
233, //;-31 9
246, //;-30 10
259, //;-29 11
272, //;-28 12
286, //;-27 13
301, //;-26 14
317, //;-25 15
333, //;-24 16
349, //;-23 17
367, //;-22 18
385, //;-21 19
403, //;-20 20
423, //;-19 21
443, //;-18 22
464, //;-17 23
486, //;-16 24
509, //;-15 25
533, //;-14 26
558, //;-13 27
583, //;-12 28
610, //;-11 29
638, //;-10 30
667, //;-9 31
696, //;-8 32
727, //;-7 33
758, //;-6 34
791, //;-5 35
824, //;-4 36
858, //;-3 37
893, //;-2 38
929, //;-1 39
965, //;0 40
1003, //;1 41
1041, //;2 42
1080, //;3 43
1119, //;4 44
1160, //;5 45
1201, //;6 46
1243, //;7 47
1285, //;8 48
1328, //;9 49
1371, //;10 50
1414, //;11 51
1459, //;12 52
1503, //;13 53
1548, //;14 54
1593, //;15 55
1638, //;16 56
1684, //;17 57
1730, //;18 58
1775, //;19 59
1821, //;20 60
1867, //;21 61
1912, //;22 62
1958, //;23 63
2003, //;24 64
2048, //;25 65
2093, //;26 66
2137, //;27 67
2182, //;28 68
2225, //;29 69
2269, //;30 70
2312, //;31 71
2354, //;32 72
2397, //;33 73
2438, //;34 74
2479, //;35 75
2519, //;36 76
2559, //;37 77
2598, //;38 78
2637, //;39 79
2675, //;40 80
2712, //;41 81
2748, //;42 82
2784, //;43 83
2819, //;44 84
2853, //;45 85
2887, //;46 86
2920, //;47 87
2952, //;48 88
2984, //;49 89
3014, //;50 90
3044, //;51 91
3073, //;52 92
3102, //;53 93
3130, //;54 94
3157, //;55 95
3183, //;56 96
3209, //;57 97
3234, //;58 98
3259, //;59 99
3283, //;60 100
3306, //;61 101
3328, //;62 102
3351, //;63 103
3372, //;64 104
3393, //;65 105
3413, //;66 106
3432, //;67 107
3452, //;68 108
3470, //;69 109
3488, //;70 110
3506, //;71 111
3523, //;72 112
3539, //;73 113
3555, //;74 114
3571, //;75 115
3586, //;76 116
3601, //;77 117
3615, //;78 118
3628, //;79 119
3642, //;80 120
3655, //;81 121
3667, //;82 122
3679, //;83 123
3691, //;84 124
3702, //;85 125
3714, //;86 126
3724, //;87 127
3735, //;88 128
3745, //;89 129
3754, //;90 130
3764, //;91 131
3773, //;92 132
3782, //;93 133
3791, //;94 134
3799, //;95 135
3807, //;96 136
3815, //;97 137
3822, //;98 138
3830, //;99 139
3837, //;100 140
3844, //;101 141
3850, //;102 142
3857, //;103 143
3863, //;104 144
3869, //;105 145
3875, //;106 146
3881, //;107 147
3887, //;108 148
3892, //;109 149
3897, //;110 150
3902, //;111 151
3907, //;112 152
3912, //;113 153
3917, //;114 154
3921, //;115 155
3926, //;116 156
3930, //;117 157
3934, //;118 158
3938, //;119 159
3942 //;120 160
};
/******************** 计算温度 ***********************************************/
// 计算结果: 0对应-40.0度, 400对应0度, 625对应25.0度, 最大1600对应120.0度.
// 为了通用, ADC输入为12bit的ADC值.
// 电路和软件算法设计: Coody
/**********************************************/
#define D_SCALE 10 //结果放大倍数, 放大10倍就是保留一位小数
u16 get_temperature(u16 adc)
{
u16 code *p;
u16 i;
u8 j,k,min,max;
adc = 4096 - adc; //Rt接地
p = temp_table;
if(adc < p[0]) return (0xfffe);
if(adc > p[160]) return (0xffff);
min = 0; //-40度
max = 160; //120度
for(j=0; j<5; j++) //对分查表
{
k = min / 2 + max / 2;
if(adc <= p[k]) max = k;
else min = k;
}
if(adc == p[min]) i = min * D_SCALE;
else if(adc == p[max]) i = max * D_SCALE;
else // min < temp < max
{
while(min <= max)
{
min++;
if(adc == p[min]) {i = min * D_SCALE; break;}
else if(adc < p[min])
{
min--;
i = p[min]; //min
j = (adc - i) * D_SCALE / (p[min+1] - i);
i = min;
i *= D_SCALE;
i += j;
break;
}
}
}
return i;
}