Leonardo (Atmega32U4)制作OLED显示RTC时钟-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7913|回复: 1

Leonardo (Atmega32U4)制作OLED显示RTC时钟

[复制链接]
发表于 2016-10-14 00:09 | 显示全部楼层 |阅读模式
    花了几天,把手头的DS1307驱动起来了,加上之前驱动的OLED显示屏,制作了一个很不错的时钟。如下图所示:

   根据RTC时钟模块的电路原理图,主要包含DS1307的时钟模块,该时钟芯片采用IIC通信协议,包含6个时间寄存器,一个控制寄存器和若干RAM寄存器。若想了解怎么用,在百度上一搜就有很多。此外这个模块上还有一个采用单线的DS18B20温度模块,一个AT24C32 EEPROM模块。EEPROM模块本例用不到。
    OLED显示屏为某宝上淘来的,1.3寸的OLED显示屏,驱动为SS1106,带有GB2312的中文字库,采用SPI协议进行通讯。
    控制芯片就是采用Leonardo上的ATmega32U4芯片,采用USBASP下载,编译环境为ICCAVR。当然,相比于Arduino编译器上编译复杂的多了,但在ICCAVR下未采用任何库函数,能更好的了解程序设计和硬件电路。闲话不多说了,需要准备以下器件:
   1)ATmega32U4和下载器;
   2)OLED显示屏,采用0.96的IIC的也可;
  3)DS1307时钟模块;
  4)带有DS18B20。

程序设计:
      程序设计完全给出,已通过实验验证,图片可证。设计时分开调试,最后合在一块。包括初始化文件、主函数头文件、DS18B20程序文件、SPI OLED程序文件以及DS1307程序设计文件。程序较长,仅供学习参考。

/****************************************************************************  
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//  作    者   : XiaoGuai
//  生成日期   : 2016-0318
//  功能描述   : 字库版 OLED SPI接口演示例程(Atmega32U4系列)
//  说    明:
               OLED驱动芯片: SSH1106
               单片机:      ATMEGA328P-PU
               晶振:        片外16Mhz石英晶振
               工作频率:    8Mhz
//========================以下为OLED显示所用到的接口===========================
//              GND       电源地
//              VCC       接5V或3.3v电源
//              CLK       PB1
//              MOSI      PB2
//              DC        PE6  Leonardo 7
//              CS1       PC6  OLED片选 Leonardo 5
//              FSO       PB3  MISO
//              CS2       PD7  字库片选  Leonardo  6              
*****************************************************************************/
#include<iom32u4v.h>
#include<AVRdef.h>
#include "main.h"
//定义RTC时间
#define SEC       00
#define MINUTE    21  
#define HOUR      23
#define WEEK      4
#define DATE      13
#define MONTH     10
#define YEAR      16

      
uint16 t1count;
uint08 Show_Out[16];
extern uint08  week_table[7][2];

//延时函数======================================================================
void delayms(uint16 u16count)
{uint16 count,i;
for(i=0;i<u16count;i++)
  {count=TCNT0;                       //读取计数器0
   while((TCNT0-count)<32) WDR();      //每次约1ms
  }
}
//----------------------------------------------------------------------------
//基本时间8us
void delay8us(uint08 u16time)
{  
   t1count=TCNT1;
   while((TCNT1-t1count)<u16time) WDR();
}
//USART发送数据--------------------------------------------------------------
void USART_Send(uint08 data)
{ while(!(UCSR1A&(1<<UDRE1)));   //等待发送缓冲器为空
  UDR1=data;                     //将数据放入缓冲器,发送数据
}
//串口发送字符串============================================================
//返回值
void SCI_Send_Str(uint08 *str)
{
  uint08 *p;
  p=str;
  while(*p) USART_Send(*(p++));   //发送一个字符  
}
//--------------------------------------------------------------------------
void DS1307_Init_Time(void)
{  
    //DS1307_Write(7,0);                               //时钟开始工作
//(void)TWI_ACK();
//DS1307_Write(7,0x90);                               //时钟输出
//(void)TWI_ACK();
   
DS1307_Write(0,0x80);            //时钟停止
    Seconds=Decimal_To_BCD(SEC);
Minutes=Decimal_To_BCD(MINUTE);
Hours=Decimal_To_BCD(HOUR);
Weeks=Decimal_To_BCD(WEEK);
Date=Decimal_To_BCD(DATE);
Month=Decimal_To_BCD(MONTH);
Year=Decimal_To_BCD(YEAR);
   
DS1307_Write(1,Minutes);
DS1307_Write(2,Hours);
DS1307_Write(3,Weeks);
DS1307_Write(4,Date);
DS1307_Write(5,Month);
DS1307_Write(6,Year);
DS1307_Write(0,Seconds&0x7F);     //时钟启动
}
//---------------------------------------------------------------------
//在屏幕上显示
void Disp_OLED(void)
{   
      
    Show_Out[0]=Time_Buffer[5];
    Show_Out[1]=Time_Buffer[4];
    Show_Out[2]=':';
    Show_Out[3]=Time_Buffer[3];
    Show_Out[4]=Time_Buffer[2];
    Show_Out[5]=':';
    Show_Out[6]=Time_Buffer[1];
    Show_Out[7]=Time_Buffer[0];
    Show_Out[8]=0;
    Dis_GB2312_Str(4,36,Show_Out);     //显示时间


   //SCI_Send_Str(Show_Out);
   //SCI_Send_Str("\n");

    Show_Out[0]='2';
    Show_Out[1]='0';
    Show_Out[2]=Time_Buffer[12];
    Show_Out[3]=Time_Buffer[11];
    Show_Out[4]=0xC4;           //年
    Show_Out[5]=0xEA;
    Show_Out[6]=Time_Buffer[10];
    Show_Out[7]=Time_Buffer[9];
    Show_Out[8]=0xd4;
    Show_Out[9]=0xc2;
    Show_Out[10]=Time_Buffer[8];
    Show_Out[11]=Time_Buffer[7];
   
    Show_Out[12]=0xC8;
    Show_Out[13]=0xd5;
    Show_Out[14]=0;
    Dis_GB2312_Str(2,16,Show_Out);     //显示年月日
   //SCI_Send_Str(Show_Out);
   //SCI_Send_Str("\n");
   
    Show_Out[0]=0xd0;                 //星期
    Show_Out[1]=0xc7;
    Show_Out[2]=0xc6;
    Show_Out[3]=0xda;
    Show_Out[4]=week_table[Time_Buffer[6]-'1'][0];
    Show_Out[5]=week_table[Time_Buffer[6]-'1'][1];
    Show_Out[6]=0;
    Dis_GB2312_Str(6,40,Show_Out);     //显示星期
   //SCI_Send_Str(Show_Out);
   //SCI_Send_Str("\n");
   
    Show_Out[0]=0xce;                 //温度
    Show_Out[1]=0xc2;
    Show_Out[2]=0xb6;
    Show_Out[3]=0xc8;
    Show_Out[4]=tem_Buff[0];
    Show_Out[5]=tem_Buff[1];
    Show_Out[6]=tem_Buff[2];
    Show_Out[7]=0xa1;
    Show_Out[8]=0xe6;
    Show_Out[9]=0;
   
    Dis_GB2312_Str(0,32,Show_Out);     //显示温度
   //SCI_Send_Str(Show_Out);
   //SCI_Send_Str("\n");
            
   
   
}
//===============主函数===================
void main(void)
{   uint16 front=0;
   
CLI();                                             //中断禁用
Init_Clock();
Init_Port();
Init_TWI();
Init_Timer0();
Init_Timer1();
SPI_Init_M0();                                     //SPI初始化时钟格式3
Init_USART1();
Initial_oled();                                //初始化OLED屏
//SEI();                                           //中断使能

CS2H;
    CS1L;
    _NOP();
Fill_screen(0xff);                                 //全屏填充
delayms(500);
Fill_screen(0);                                    //清屏  
delayms(100);            


//DS1307_Init_Time();                             //一般不需要打开
delayms(100);

                 
while(1)
{ WDR();

   //SCI_Send_Str("\n");
   RTC_Read();                        //读取时间
  //SCI_Send_Str(
     
      DS18B20_String();                 //读取温度
   //SCI_Send_Str(tem_Buff);
   
   Disp_OLED();                      //在屏幕上显示     
    delayms(900);
   
}

}  
//=============================================================================


/**************************************************************
*************************************************************/
#include<iom32u4v.h>
#include<AVRdef.h>
#include "main.h"
//-----------------------------------------------------------------------------
//初始化时钟-------------------------------------------------------------------
void Init_Clock(void)
{//OSCCAL = 0x96;                 //时钟矫正至8.0Mhz,page38
CLKPR  = 0x80;                   //时钟分频器使能CLKPR_CLKPCE  
CLKPR  = 0x01;                   //系统时钟2分频,p39(0>1;1>2;...8>256)
}
//初始化USART----------------------------------------------------------------
//初始化串口
void Init_USART1(void)
{
  UCSR1A = 0;                       //异步正常模式
  UCSR1B |= BIT(TXEN1);            //发送接收使能
  UCSR1C = 0x06;                   //正常模式无校验,8位数据位
  UBRR1H = 0;
  UBRR1L =8;                      //57600波特率,错误率-3.5%
}
//-----------------------------------------------------------------------
void Init_Port(void)
{
  DDRC  |= BIT(DDC6);              //PC6 作为片选输出   
  DDRD  |= BIT(DDD7);       //PD7 作为片选输出  
  DDRD  &=~BIT(DDD4);
  PORTD&=~BIT(PORTD4);                //置为低                        
  PORTB=0xff;
  DDRE  |=(1<<DDE6);                    //DC输出
              

}
//初始化定时器------------------------------------------------------------
void Init_Timer0(void)
{
  //PRR0=0b00000001;          //ADC抑制
  //PRR1=0b10011000;      //TC3 TC4抑制,USB抑制
  TCCR0A  = 0x00;          //正常模式
  TCCR0B  = 0x04;          //预分频器256分频,每次计数32us,page91
}
//初始化定时器1------------------------------------------------------------
void Init_Timer1(void)
{
  TCCR1A  = 0x00;          //正常模式
  TCCR1B  = 0x03;          //预分频器64分频,每次计数8us,page91
}
void SPI_High_Rate(void)
{
  //最高操作速率不能高于25Mbps
  SPCR &= 0x5C;   //BR=busclk/(SPPR *SPR )=8M/4=2M ,page147
   //SPCR = (1<<SPE)|(1<<MSTR);              
}
//SPI主机初始化,低速模式125k==========================================================
void SPI_Init_M0(void)
{                                     //SPI模式0
  DDRB|= (1<<DDB2)|(1<<DDB1);        //设置MOSI 和SCK 为输出,其他为输入
  SPCR = 0b01010001;                       //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}
//SPI主机初始化,低速模式125k==========================================================
void SPI_Init_M3(void)
{                                     //SPI模式3
  DDRB|= (1<<DDB2)|(1<<DDB1);        //设置MOSI 和SCK 为输出,其他为输入
  SPCR = 0b01011001;                       //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}   
//------------------------------------------------------------------------
//DS1307时钟频率4Mhz,设置单片机比特率
//SCL frequency=cpu clock/(16+2(TWBR)*(prescalerValue))
void Init_TWI(void)
{
  //TWCR = 0x00;                      //中止I2C
  TWBR =   24;                       //比特率寄存器为24,产生9615波特率
  TWSR = 0x03;                      //比特率预分频因子16,page194
  //TWAR=0xFF;                     //工作于主机模式不需要此地址
// TWCR = BIT(TWEN);                 //TWI使能,TWINF写1清零
  
}


                              /****************************************************************************  
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//  作    者   : XiaoGuai
//  生成日期   : 2016-10-09
//  功能描述   : DS1307 IIC时钟
//  说    明:
         
               单片机:      ATMEGA32U4-AU
               晶振:        片外16Mhz石英晶振
               工作频率:    8Mhz
//========================IIC DS1307用到的引脚定义===========================
//              GND       电源地
//              VCC       接5V或3.3v电源
//              SDA       PD1 SDA
//              SCL       PD3 SCL
//              DS        PD4 Leonardo D4
            
*****************************************************************************/
#include<iom32u4v.h>
#include<AVRdef.h>
#include "main.h"

uint16 u16sensorValue=0;
uint08 u08data[8];        //ds1307读出数据
uint08 Seconds=0;
uint08 Minutes=0;
uint08 Hours=0;
uint08 Weeks=0;
uint08 Date=0;
uint08 Month=0;
uint08 Year=0;

uint08 disp_tab[]={'0','1','2','3','4','5','6','7','8','9'};
uint08  week_table[7][2]={0xd2,0xbb,0xb6,0xfe,0xc8,0xfd,0xcb,0xc4,0xce,0xe5,0xc1,0xf9,0xc8,0xd5};
uint08 Time_Buffer[16];
      
//------------------------------------------------------------------------
//启动I2C
void TWI_Start(void)                           //refer to page198
{
    TWCR = BIT(TWINT)|BIT(TWSTA)|BIT(TWEN);   //TWI start,主机模式,page149
while(!(TWCR&(1<<TWINT))) ;                 //等待TWINF置位以及收到应答信号
}
//-------------------------------------------------------------------------------
//主机发送一个字节
void TWI_Write(uint08 data)
{   TWDR = data;                               //将字符写入数据寄存器
   TWCR = (1<<TWINT)|(1<<TWEN);              //启动发送地址及数据,page198
   while(!(TWCR&(1<<TWINT)));               //等待TWINF置位,SLA+W或data已发出
}
//-------------------------------------------------------------------------------
//I2C应答函数-------------------------------------------------------------------
uint08 TWI_ACK(void)
{ // _NOP();                                  //延时1个指令周期
  return (TWSR&0xF8);                      //返回TWI状态,高5位
}
//-------------------------------------------------------------------------------
//总线读出一个字符返回读出的字符
uint08 TWI_READ(void)
{  TWCR = BIT(TWINT)|BIT(TWEA)|BIT(TWEN);
   while(!(TWCR&BIT(TWINT)));
   return(TWDR);                            //返回读出的数据
}
//---------------------------------------------------------------------------------
//向I2C slave写入数据,第一个参数是页选择为0和1。第二个是字节地址0xFF,第三个参数为字节数据
void DS1307_Write(uint08 startAdd,uint08 data)
{   TWI_Start();                                 //开启发送     
TWI_Write(DS1307_CTRL_ID);                 //发送从机地址
if(TWI_ACK()==SLAW)                        //应答
  TWI_Write(startAdd);                     //发送字节地址
if(TWI_ACK()==DataOKW)                   //应答
  TWI_Write(data);                          //发送数据
  (void)TWI_ACK();                               //写入数据应答
  TWI_Stop();                             //发送停止信号
  //_NOP();                                    //延时
  delay8us(10);
}

//--------------------------------------------------------------------------------
//从I2C读取数据参数1为变量地址,参数2为页选择,参数3为字节地址,参数4为读取数量
//读取模式为连续读
void DS1307_Read(uint08 startAdd)
{   uint08 u08i;  
TWI_Start();                                  //发送起始信号                    
TWI_Write(DS1307_CTRL_ID);                  //写入地址及页选择位
if(TWI_ACK()==SLAW)                         //地址发送应答
   TWI_Write(startAdd);                             //写入字节地址
if(TWI_ACK()==DataOKW)                      //发送页码和字节地址
    TWI_Stop();

  
   _NOP();
   _NOP();
TWI_Start();                                //再一次开始
  
TWI_Write(DS1307READ);                      //写入读地址及页选择位
(void)TWI_ACK();                            //读应答,返回值有误

for(u08i=startAdd;u08i<6;u08i++)
   {
    u08data[u08i]=TWI_READ();                         //从总线读一个字节存入缓冲区
    (void)TWI_ACK();                                   //应答
   }
     TWCR = BIT(TWINT)|BIT(TWEN);                        //最后一位无应答
     while(!(TWCR&BIT(TWINT)));  
   u08data[6]=TWDR;                                   //从总线读一个字节存入中间量


TWI_Stop();                                        //发送停止信号   
}
//-------------------------------------------------------------------------------
//十进制转换成BCD码
uint08 Decimal_To_BCD(uint08 tcmp)
{uint08 a,b,c;
a=tcmp;
b=0;
if(a>=10)
{while(a>=10)
  {a=a-10;
   b=b+16;
   c=a+b;
   tcmp=c;
  }
}
return tcmp;
}
//-------------------------------------------------------------------------------
//BCD码转换成十进制
uint08 BCD_To_Decimal(uint08 tcmp)
{uint08 a,b,c;
a=tcmp&0x7F;            //只有低6位
b=0;
if(a>=16)
{while(a>=16)
  {a=a-16;
   b=b+10;
   c=a+b;
   tcmp=c;
  }
}
return tcmp;
}
//----------------------------------------------------------------------------
void RTC_Read(void)
{

DS1307_Read(0);               //起始地址为0
//u08data[7]=0;
//SCI_Send_Str(u08data);

Seconds=BCD_To_Decimal(u08data[0])&0x3F;
Minutes=BCD_To_Decimal(u08data[1])&0x3F;
Hours=BCD_To_Decimal(u08data[2])&0x1F;
Weeks=u08data[3]&0x07;              //星期不需要转换
Date=BCD_To_Decimal(u08data[4])&0x1F;
Month=BCD_To_Decimal(u08data[5])&0x0F;
Year=BCD_To_Decimal(u08data[6])&0x7F;
//显示缓冲区,变成ASCII码
Time_Buffer[0]=disp_tab[Seconds%10];        //个位秒
Time_Buffer[1]=disp_tab[Seconds/10];        //十位秒

Time_Buffer[2]=disp_tab[Minutes%10];        //个位分
Time_Buffer[3]=disp_tab[Minutes/10];        //十位分

Time_Buffer[4]=disp_tab[Hours%10];        //个位时
Time_Buffer[5]=disp_tab[Hours/10];        //十位时

Time_Buffer[6]=disp_tab[Weeks];        //周

Time_Buffer[7]=disp_tab[Date%10];         //个位日期
Time_Buffer[8]=disp_tab[Date/10];         //十位日期

Time_Buffer[9]=disp_tab[Month%10];         //个位月份
Time_Buffer[10]=disp_tab[Month/10];         //十位月份   
      
Time_Buffer[11]=disp_tab[Year%10];         //个位年
Time_Buffer[12]=disp_tab[Year/10];        //十位年
Time_Buffer[13]=disp_tab[0];              //百位年
Time_Buffer[14]=disp_tab[2];              //千位年

Time_Buffer[15]=0;                       //字符串结束标志

}
//=============================================================================

                              /****************************************************************************  
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//  作    者   : XiaoGuai
//  生成日期   : 2016-10-09
//  功能描述   : DS18B20温度
//  说    明:
         
               单片机:      ATMEGA32U4-AU
               晶振:        片外16Mhz石英晶振
               工作频率:    8Mhz
//========================DS18B20用到的引脚定义===========================
//              GND       电源地
//              VCC       接5V或3.3v电源
//              DS        PD4 Leonardo D4
            
*****************************************************************************/
#include<iom32u4v.h>
#include<AVRdef.h>
#include "main.h"


uint08 temp;
uint08 DS_Data[3];  
uint08 tem_Buff[4];
  
void SCI_Send_Str(uint08 *str);     
//------------------------------------------------------------------
uint08 DS18B20_Init(void)
{
uint08 ret;
CLI();
while(!READ_1WIRE_BUS) WDR();    //等待总线为高

DS_LOW;
  delay8us(63);               //至少延时480us
DS_HIGH;
  delay8us(6);                //延时15us-60us
if(READ_1WIRE_BUS)
   ret = FAULT;
else
   ret = RIGHT;
   delay8us(63);
  SEI();
   return ret;
}
//-----------------------------------------------------------------------------
//向DS18B20读取8位数据
uint08 ds18b20_read(void)
{
uint08 data=0;
uint08 i=0;
CLI();
for(i=0;i<8;i++)
{
data>>=1;
//DS_HIGH;
//while(!READ_1WIRE_BUS) WDR();    //等待总线为高
//delay8us(1);               //延时>1us

DS_LOW;
delay8us(1);               //延时>1us
DS_HIGH;
delay8us(1);               // <15us
if(READ_1WIRE_BUS)
  data|=0x80;
  delay8us(7);              //>45us
}
SEI();
return data;
}
//------------------------------------------------------------
//单总线写一字节
void ds18b20_write(uint08 data)
{
  uint08 i=0;
  CLI();
  for(i=0;i<8;i++)
  {
    if(data&0x01)
    {
      DS_LOW;
      delay8us(1);//8us
      DS_HIGH;
      delay8us(7);//55us
    }
    else
    {
      DS_LOW;
      delay8us(8);//55us
      DS_HIGH;
      delay8us(1);//8us
    }
    data>>=1;
  }
  SEI();
}
//-----------------------------------------------------------------------------------
//执行转换
uint08 Ds18b20_Convert(void)
{
  //发送转换命令
  if(DS18B20_Init()==FAULT)
   return FAULT;
  //SCI_Send_Str("test1\n");  
  
  
  ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,总线上只有一个器件时,或对总线所有器件操作
  
  ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令
  
  //等待转换完成,ds18b20默认转换精度为12位,此时最大转换时间为750ms
  delay8us(125);
  
  //读温度字节
if(DS18B20_Init()==FAULT)  return FAULT;
  //SCI_Send_Str("test2\n");  
  ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
  ds18b20_write(DS18B20_READ_RAM); //读RAM命令
  DS_Data[0]=ds18b20_read();
  DS_Data[1]=ds18b20_read();
   //SCI_Send_Str("test3\n");  

  return RIGHT;
}
//----------------------------------------------------------------------------
//根据DS18B20中读的温度字节,计算实际温度值
sint08 Get_Temperature(void)
{
  sint08 temp ;
  uint32 value;
  uint16 u16tmp;
  uint08 flag=0;
  
  u16tmp=(DS_Data[1]*256)+DS_Data[0];
  
  if((DS_Data[1]&0xf8)==0xf8) //若负温度,从补码转换(取反加一)
  {
    flag=1;
    u16tmp=~u16tmp;
    u16tmp++;
  }
  u16tmp&=0x07ff;    //确保前5位为0
  
  //乘0.0625操作,为此本函数只适用于DS18B20 12位转换(默认)时
  value=((uint32)u16tmp)*625;
  value/=10000;
  
  temp=(sint08)value;
  
  if(flag)
    temp|=0x80;//变负数
   
  return temp;
}
//------------------------------------------------------------------------
void DS18B20_String(void)
{   sint08 temp=0;
   if(Ds18b20_Convert()==RIGHT)
    {
     temp=Get_Temperature();
  
     if(temp>=0)
  {
   tem_Buff[0]=' ';         //空格

  }
  else
  {
  tem_Buff[0]='-';      //空格
  }   
      temp&=0x7F;     //只取<99
   tem_Buff[1]=temp/10+'0';
   tem_Buff[2]=temp%10+'0';
   tem_Buff[3]=0;
   
   
    }
}
//---------------------------------------------------------------------------------

                              /****************************************************************************  
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//  参    考   :中景园电子
//  作    者   : XiaoGuai
//  生成日期   : 2016-0318
//  功能描述   : 字库版 OLED SPI接口演示例程(Atmega32U4系列)
//  说    明:
               OLED驱动芯片: SSH1106
               单片机:      ATMEGA328P-PU
               晶振:        片外16Mhz石英晶振
               工作频率:    8Mhz
//========================以下为OLED显示所用到的接口===========================
//              GND       电源地
//              VCC       接5V或3.3v电源
//              CLK       PB1
//              MOSI      PB2
//              DC        PE6
//              CS1       PC6  OLED片选
//              FSO       PB3  MISO
//              CS2       PD7  字库片选              
*****************************************************************************/
#include<iom32u4v.h>
#include<AVRdef.h>
#include "main.h"


//SPI数据传输,采用轮询=========================================================
uint08 SPI_Tran_Byte(uint08 data)
{
SPDR = data;                                //启动数据传输
while(!(SPSR & (1<<SPIF)));                 //等待传输结束
return SPDR;               //接收字符
}
//写指令到oled模块==============================================================
void tran_cmd_oled(uint08 data)   
{
        
  DCL;                //DC=0
  _NOP();
  (void)SPI_Tran_Byte(data);
}
//写数据到oled模块==============================================================
void tran_dat_oled(uint08 data)   
{
  DCH;               //DC=1
  _NOP();      
  (void)SPI_Tran_Byte(data);
}
//OLED模块初始化================================================================
void Initial_oled(void)
{
CS1L;                 //CS1低
CS2H;                 //CS2高
   
delayms(20);        
tran_cmd_oled(0xAE); //显示关
tran_cmd_oled(0x20); //设置内存寻址模式
tran_cmd_oled(0x10); //00,水平寻址模式;01,垂直寻址模式;10,页寻址模式(RESET);11,无效
tran_cmd_oled(0xb0); //设置页寻址模式的页起始地址,0-7
tran_cmd_oled(0xc8); //设置COM口输出扫描方向
tran_cmd_oled(0x02); //设置y的低地址
tran_cmd_oled(0x10); //设置y的低地址
tran_cmd_oled(0x40); //设置开始行地址
tran_cmd_oled(0x81); //设置对比控制寄存器
tran_cmd_oled(0x7f);
tran_cmd_oled(0xa1); //设置段 0 - 127
tran_cmd_oled(0xa6); //设置正常显示
tran_cmd_oled(0xa8); //设置多路复用率(1 -64)
tran_cmd_oled(0x3F); //
tran_cmd_oled(0xa4); //0xa4,输出跟踪存储器内容;0xa5,输出忽略存储器内容
tran_cmd_oled(0xd3); //设置显示偏移
tran_cmd_oled(0x00); //不偏移
tran_cmd_oled(0xd5); //设置显示时钟分频系数/晶振频率
tran_cmd_oled(0xf0); //设置分频系数
tran_cmd_oled(0xd9); //设置预充电周期
tran_cmd_oled(0x22); //
tran_cmd_oled(0xda); //设置端口硬件配置
tran_cmd_oled(0x12);
tran_cmd_oled(0xdb); //设置vcomh
tran_cmd_oled(0x20); //0x20,0.77xVcc
tran_cmd_oled(0x8d); //DC-DC使能
tran_cmd_oled(0x14); //
tran_cmd_oled(0xaf); //-打开Oled面板
CS1H;                    
}
//设置行和列================================================================
void Oled_Position(uint08 x,uint08 y)
{
tran_cmd_oled(0xb0+x);                    //设置行
tran_cmd_oled(((y&0xf0) >> 4)|0x10);   //设置列地址的高4位
tran_cmd_oled((y&0x0f)|0x00);           //设置列地址的低4位
}
//全屏填充=================================================================
void Fill_screen(uint08 dat)
{
uint08 i,j;
CS2H;
CS1L;              
for(i=0;i<8;i++)
{
  tran_cmd_oled(0xb0+i);
  tran_cmd_oled(0x02);
  tran_cmd_oled(0x10);
  for(j=0;j<128;j++)
   tran_dat_oled(dat);        //全部写dat
  
}
    //Oled_Position(0,1);               //初始化位置
  CS1H;
}
/*从相关地址(addrHigh:地址高字节,addrMid:地址中字节,addrLow:地址低字节)中连续读出DataLen个字节的数据到 pBuff的地址*/
/*连续读取*/
void Get_bytes_from_ROM(uint08 addrHigh,uint08 addrMid,uint08 addrLow,uint08 *pBuff,uint08 DataLen )
{  
uint08 i;
CS2L;                        //字库芯片片选
CS1H;
(void)SPI_Tran_Byte(0x03);   //提取数据命令
(void)SPI_Tran_Byte(addrHigh);
(void)SPI_Tran_Byte(addrMid);
(void)SPI_Tran_Byte(addrLow);
for(i=0;i<DataLen;i++)
     *(pBuff++) =SPI_Tran_Byte(0xff);
CS2H;
//_NOP();
}
//显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标
//x表示行,y表示列列变化不连续
void Dis_grap_16x16(uint08 x,uint08 y,uint08 *dp)
{
uint08 i,j;
  CS1L;
for(j=0;j<2;j++,x++)
{
   Oled_Position(x,y+1);
   for(i=0;i<16;i++,dp++)
  tran_dat_oled(*dp);     //写数据到LCD,每写完一个8位的数据后列地址自动加1
}
CS1H;
}
/*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/
void Dis_grap_8x16(uint08 x,uint08 y,uint08 *dp)
{
uint08 i,j;
CS1L;                  
for(j=0;j<2;j++,x++)
{
  Oled_Position(x,y+1);
  for(i=0;i<8;i++,dp++)
  tran_dat_oled(*dp);     /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/
  
}
CS1H;
}
/*****************************************************************
功能:显示GB2312汉字字符
x行,取值范围:0,2,4,6
y列,取值范围:1—128
ch[] 需要输出的字符串
StrAdd 需要输出的字符地址
返回值 0 完成,非0 页满
*******************************************************************/
uint16 Dis_GB2312_Str(uint08 x,uint08 y,cuint08 ch[])
{   uint32 fontadd=0;                     //32位数据地址
uint08 addrHigh,addrMid,addrLow ;
uint08 fontbuf[32];
uint08 StrAdd=0;
  
while(ch[StrAdd])                       //数据值不为0
{
  if((ch[StrAdd]>175)&&(ch[StrAdd]<248)&&(ch[StrAdd+1]>160))
  {      
                                           //国标简体(GB2312)汉字在晶联讯字库IC中的地址由以下公式来计算:
                                           //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0
                                           //由于担心8位单片机有乘法溢出问题,所以分三部取地址
   fontadd = (ch[StrAdd]-176)*94;
   fontadd += (ch[StrAdd+1]-161)+846;
   fontadd = fontadd*32;
   
   addrHigh =(fontadd&0xff0000)>>16;  //地址的高8位,共24位
   addrMid =(fontadd&0xff00)>>8;      //地址的中8位,共24位
   addrLow =fontadd&0xff;             //地址的低8位,共24位
   
   Get_bytes_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32 );//取32个字节的数据,存到"fontbuf[32]"
   Dis_grap_16x16(x,y,fontbuf);                             //显示汉字到OLED上,y为页地址,x为列地址,fontbuf[]为数据
   StrAdd+=2;                        //地址加2
   if(y<=112) y+=16;
   else if(x<=4) {x+=2;y=1;}         //到头了换行
       else return PAGEFILL;           //返回当前地址
  }
  else if((ch[StrAdd]>160)&&(ch[StrAdd]<164)&&(ch[StrAdd+1]>160))
  {      
                                            //Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0
   fontadd = (ch[StrAdd]- 0xa1)*94;
   fontadd += (ch[StrAdd+1]-0xa1);
   fontadd = fontadd*32;
   
   addrHigh = (fontadd&0xff0000)>>16;  
   addrMid = (fontadd&0xff00)>>8;     
   addrLow = fontadd&0xff;   
         
   Get_bytes_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32 );
   Dis_grap_16x16(x,y,fontbuf);
   StrAdd+=2;
   if(y<=112) y+=16;
   else if(x<=4) {x+=2;y=1;}     //到头了换行
       else return PAGEFILL ;       //返回当前地址
  }
  else if((ch[StrAdd]>31)&&(ch[StrAdd]<127))
  {      
   fontadd = ch[StrAdd]- 0x20;
   fontadd = fontadd*16;
   fontadd = fontadd+0x3cf80;   
   addrHigh = (fontadd&0xff0000)>>16;
   addrMid = (fontadd&0xff00)>>8;
   addrLow = fontadd&0xff;
   Get_bytes_from_ROM(addrHigh,addrMid,addrLow,fontbuf,16 );
   Dis_grap_8x16(x,y,fontbuf);
            StrAdd++;
   if(y<=120) y+=8;
   else if(x<=4) {x+=2;y=1;}        //到头了换行
       else return PAGEFILL ;          //返回当前地址
  }

}
return RIGHT;

}
//==============================================================================

#ifndef MAIN_H
#define MAIN_H
//数据类型宏定义
typedef unsigned char uint08;
typedef signed   char sint08;
typedef unsigned int  uint16;
typedef signed   int  sint16;
typedef unsigned long uint32;
typedef const unsigned char cuint08;

#define CS1L  PORTC&=0xBF      //CS1低
#define CS1H  PORTC|=0x40      //CS1高
#define CS2L  PORTD&=0x7F      //CS2低
#define CS2H  PORTD|=0x80      //CS2高
#define DCH   PORTE|=0x40      //DC高
#define DCL   PORTE&=0xBF      //DC低
//DS1307         
#define DS1307WRIT  0xd0    //写+地址
#define DS1307READ  0xd1    //读+地址
#define SLAW         0x18   //模块正确地址应答常量写 page238
#define DataOKW      0x28   //模块正确数据写应答常量
#define SLAR         0x40   //地址收到ok,page204
#define DataOKR      0x50   //数据收到ok
#define DS1307_BASE_YR 2000
#define DS1307_CTRL_ID 0B11010000  //DS1307 地址  
#define  TWI_Stop()    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)   //停止   
//DS18B20
#define DS_HIGH          DDRD&=~(1<<DDD4)          //作为输出
#define DS_LOW           DDRD|=(1<<DDD4)
#define READ_1WIRE_BUS   PIND&(1<<PIND4)          //读取数据
#define FAULT  1
#define RIGHT  0
#define PAGEFILL  2      //页满
#define DS18B20_READ_ROM 0x33
#define DS18B20_MATCH_ROM 0X55
#define DS18B20_SKIP_ROM 0XCC
#define DS18B20_SEARCH_ROM 0XF0
#define DS18B20_ALARM_SEARCH_ROM 0XEC
#define DS18B20_WRITE_RAM 0X40
#define DS18B20_READ_RAM 0XBE
#define DS18B20_COPY_RAM 0X48
#define DS18B20_CONVERT_TEM 0X44
//变量声明
extern  uint08 Seconds;
extern  uint08 Minutes;
extern  uint08 Hours;
extern  uint08 Weeks;
extern  uint08 Date;
extern  uint08 Month;
extern  uint08 Year;
extern  uint08 Time_Buffer[16];
extern  uint08 tem_Buff[4];
//以下是函数声明
void Init_Clock(void);
void Init_Port(void);
void Init_Timer0(void);
void Init_USART1(void);
void SPI_High_Rate(void);
void SPI_Init_M3(void);
void SPI_Init_M0(void);
void Init_TWI(void);
void Init_Timer1(void);
void delay8us(uint08 u16time);
void delayms(uint16 u16count);
void RTC_Read(void);
uint08 Decimal_To_BCD(uint08 tcmp);
void DS1307_Write(uint08 startAdd,uint08 data);
uint08 TWI_ACK(void);
uint16 Dis_GB2312_Str(uint08 x,uint08 y,cuint08 ch[]);
void Initial_oled(void);
void Fill_screen(uint08 dat);
uint08 Ds18b20_Convert(void);
sint08 Get_Temperature(void);
void SCI_Send_Str(uint08 *str) ;
void DS18B20_String(void);
#endif
//---------------------------------------------------------------------------------
IMG_20161013_234426.jpg
IMG_20161013_234416.jpg
IMG_20161013_234432.jpg

RTC时钟原理图

RTC时钟原理图
连接图.jpg

OLED屏

OLED屏
发表于 2016-10-14 22:45 | 显示全部楼层
顶啊  求助区 [未解决] 求助 无法创建项目文件夹 急急急   大神们谁来帮我解决下!!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 03:27 , Processed in 0.081017 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表