STC8H IO设置 中断号 下载 仿真 引脚封装

发布于:2025-07-15 ⋅ 阅读:(17) ⋅ 点赞:(0)

*************  本程序功能说明  **************

本例程基于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;
}

 


网站公告

今日签到

点亮在社区的每一天
去签到