花了几天,把手头的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
//---------------------------------------------------------------------------------
|