ATmega 328驱动SPI模式的OLED屏代码-Arduino中文社区 - Powered by Discuz! Archiver

希岩 发表于 2016-3-20 19:48

ATmega 328驱动SPI模式的OLED屏代码

本帖最后由 希岩 于 2020-5-28 13:10 编辑

在淘宝上淘了个OLED屏,花了不少钱*_*。1.3寸带中文字库的OLED屏,单色白。驱动为SSH1106,卖家给的例程是51和stm的。想来手头只有AVR的,就改写原来的程序了。花了不少时间终于完成了。不多说,上代码。适用于3.3V-5V供电,适用于ATmega48 ATmega48(去掉图片数组) ATmega88 ATmega168 ATmega328芯片。编译环境为ICCAVR7 ,适用于Arduino IDE(没亲自尝试,自己试吧)
主函数文件:
/****************************************************************************
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//参    考   :中景园电子
//作    者   : XiaoGuai
//生成日期   : 2016-0318
//功能描述   : 字库版 OLED SPI接口演示例程(Atmega328系列)
//说    明:
               OLED驱动芯片: SSH1106
               单片机:      ATMEGA328P-PU
               晶振:      片外16Mhz石英晶振
               工作频率:    8Mhz
//========================以下为OLED显示所用到的接口===========================
//            GND       电源地
//            VCC       接5V或3.3v电源
//            CLK       PB5
//            MOSI      PB3
//            DC      PC0
//            CS1       PB2OLED片选
//            FSO       PB4MISO
//            CS2       PB1字库片选            
********************************************************************************/
#include<iom328pv.h>
#include<AVRdef.h>
#include "main.h"
#include "picturetable.h"      //只能声明一次
#define CS1LPORTB&=0xfb      //CS1低
#define CS1HPORTB|=0x04      //CS1高
#define CS2LPORTB&=0xfd      //CS2低
#define CS2HPORTB|=0x02      //CS2高

uint32fontaddr=0;                     //数据地址      
uint08jiong1[]={                      //使用软件生成文字:囧点阵16x16
0x00,0xFE,0x82,0x42,0x22,0x1A,
0x02,0x02,0x02,0x0A,0x12,0x62,
0x02,0xFE,0x00,0x00,0x00,0xFF,
0x40,0x40,0x40,0x7F,0x41,0x41,
0x41,0x7F,0x40,0x40,0x40,0xFF,
0x00,0x00
};
//延时函数======================================================================
void delayms(uint16 u16count)
{uint16 count,i;
for(i=0;i<u16count;i++)
{count=TCNT0;                     //读取计数器0
   while((TCNT0-count)<32)WDR();      //每次约1ms
}
}
//SPI数据传输,采用轮询=========================================================
uint08 SPI_Trans_Byte(sint08 data)
{
SPDR = data;                              //启动数据传输
while(!(SPSR & (1<<SPIF)));               //等待传输结束
return SPDR;                           //接收字符
}
//写指令到oled模块==============================================================
void transfer_cmd_oled(uint08 data)   
{
PORTC&=0xfe;       //DC=0 PC0=0
_NOP();
(void)SPI_Trans_Byte(data);
}
//写数据到oled模块==============================================================
void transfer_dat_oled(uint08 data)   
{
PORTC|=0x01;       //DC=1 PC0=1
_NOP();      
(void)SPI_Trans_Byte(data);
}
//OLED模块初始化================================================================
void Initial_oled(void)
{
CS1L;               //CS1低
CS2H;               //CS2高
   
delayms(20);      
transfer_cmd_oled(0xAE); //显示关
transfer_cmd_oled(0x20); //设置内存寻址模式
transfer_cmd_oled(0x10); //00,水平寻址模式;01,垂直寻址模式;10,页寻址模式(RESET);11,无效
transfer_cmd_oled(0xb0); //设置页寻址模式的页起始地址,0-7
transfer_cmd_oled(0xc8); //设置COM口输出扫描方向
transfer_cmd_oled(0x02); //设置y的低地址
transfer_cmd_oled(0x10); //设置y的低地址
transfer_cmd_oled(0x40); //设置开始行地址
transfer_cmd_oled(0x81); //设置对比控制寄存器
transfer_cmd_oled(0x7f);
transfer_cmd_oled(0xa1); //设置段 0 - 127
transfer_cmd_oled(0xa6); //设置正常显示
transfer_cmd_oled(0xa8); //设置多路复用率(1 -64)
transfer_cmd_oled(0x3F); //
transfer_cmd_oled(0xa4); //0xa4,输出跟踪存储器内容;0xa5,输出忽略存储器内容
transfer_cmd_oled(0xd3); //设置显示偏移
transfer_cmd_oled(0x00); //不偏移
transfer_cmd_oled(0xd5); //设置显示时钟分频系数/晶振频率
transfer_cmd_oled(0xf0); //设置分频系数
transfer_cmd_oled(0xd9); //设置预充电周期
transfer_cmd_oled(0x22); //
transfer_cmd_oled(0xda); //设置端口硬件配置
transfer_cmd_oled(0x12);
transfer_cmd_oled(0xdb); //设置vcomh
transfer_cmd_oled(0x20); //0x20,0.77xVcc
transfer_cmd_oled(0x8d); //DC-DC使能
transfer_cmd_oled(0x14); //
transfer_cmd_oled(0xaf); //-打开Oled面板
CS1H;                  
}
//设置行和列================================================================
void Oled_Position(uint08 x,uint08 y)
{
transfer_cmd_oled(0xb0 + x);                  //设置行
transfer_cmd_oled(((y&0xf0) >> 4)|0x10);   //设置列地址的高4位
transfer_cmd_oled((y&0x0f)|0x00);         //设置列地址的低4位
}
//全屏填充=================================================================
void Fill_screen(uint08 dat)
{
uint08 i,j;
CS2H;
CS1L;            
for(i=0;i<8;i++)
{
transfer_cmd_oled(0xb0+i);
transfer_cmd_oled(0x02);
transfer_cmd_oled(0x10);
for(j=0;j<128;j++)
   transfer_dat_oled(dat);      //全部写dat

}
Oled_Position(0,1);               //初始化位置
CS1H;
}

//从晶联讯字库IC中取汉字或字符数据(1个字节)
static uint08 get_data_from_ROM(void)
{ //_NOP();
return(SPI_Trans_Byte(0xff));
}
/*从相关地址(addrHigh:地址高字节,addrMid:地址中字节,addrLow:地址低字节)中连续读出DataLen个字节的数据到 pBuff的地址*/
/*连续读取*/
void get_nbytes_data_from_ROM(uint08 addrHigh,uint08 addrMid,uint08 addrLow,uint08 *pBuff,uint08 DataLen )
{
uint08 u8temp;
CS2L;                     //字库芯片片选
CS1H;
(void)SPI_Trans_Byte(0x03);   //提取数据命令
(void)SPI_Trans_Byte(addrHigh);
(void)SPI_Trans_Byte(addrMid);
(void)SPI_Trans_Byte(addrLow);
for(u8temp = 0; u8temp < DataLen; u8temp++ )
   // *(pBuff+u8temp) =get_data_from_ROM();
   *(pBuff+u8temp) =SPI_Trans_Byte(0xff);
CS2H;
_NOP();
}
//显示128x64点阵图像===================================================================
void display_128x64(cuint08 *dp)
{
uint08 i,j;
CS1L;
for(j=0;j<8;j++)
{
Oled_Position(j,0);
for (i=0;i<128;i++,dp++)
   transfer_dat_oled(*dp);   /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/

}
CS1H;
}
//显示5*7点阵图像、ASCII, 或5x7点阵的自造字符、其他图标
void display_graphic_5x7(uint08 x,uint08 y,uint08 *dp)
{
uint08 col_cnt;
uint08 page_address;
uint08 column_address_L,column_address_H;

page_address = 0xb0+x-1;
CS1L;

column_address_L =(y&0x0f)-1;
column_address_H =((y>>4)&0x0f)+0x10;

transfer_cmd_oled(page_address);   //设置页地址
transfer_cmd_oled(column_address_H); /*Set MSB of y Address*/
transfer_cmd_oled(column_address_L); /*Set LSB of y Address*/

for (col_cnt=0;col_cnt<6;col_cnt++)
{
transfer_dat_oled(*dp);
dp++;
}
CS1H;
}
//显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标
//x表示行,y表示列列变化不连续
void display_graphic_16x16(uint08 x,uint08 y,uint08 *dp)
{
uint08 i,j;
CS1L;
for(j=2;j>0;j--,x++)
{
Oled_Position(x,y);
for (i=0;i<16;i++,dp++)
   transfer_dat_oled(*dp);   //写数据到LCD,每写完一个8位的数据后列地址自动加1
}
CS1H;
}
/*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/
void display_graphic_8x16(uint08 x,uint08 y,uint08 *dp)
{
uint08 i,j;
CS1L;                  
for(j=2;j>0;j--)
{
Oled_Position(x,y);
for (i=0;i<8;i++)
{
   transfer_dat_oled(*dp);   /*写数据到LCD,每写完一个8位的数据后列地址自动加1*/
   dp++;
}
x++;
}
CS1H;
}
/*****************************************************************
功能:显示GB2312汉字字符
y行,取值范围:0,2,4,6
x列,取值范围:1—128
*******************************************************************/
void display_GB2312_string(uint08 y,uint08 x,uint08 text[])
{   
uint08 i=0;
uint08 addrHigh,addrMid,addrLow ;
uint08 fontbuf;
   
while(text>0)
{
if(((text>=0xb0) &&(text<=0xf7))&&(text>=0xa1))
{      
   //国标简体(GB2312)汉字在晶联讯字库IC中的地址由以下公式来计算:
   //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0
   //由于担心8位单片机有乘法溢出问题,所以分三部取地址
   fontaddr = (text- 0xb0)*94;
   fontaddr += (text-0xa1)+846;
   fontaddr = (uint32)(fontaddr*32);
   
   addrHigh = (fontaddr&0xff0000)>>16;/*地址的高8位,共24位*/
   addrMid = (fontaddr&0xff00)>>8;      /*地址的中8位,共24位*/
   addrLow = fontaddr&0xff;      /*地址的低8位,共24位*/
   get_nbytes_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32 );/*取32个字节的数据,存到"fontbuf"*/
   display_graphic_16x16(y,x,fontbuf);/*显示汉字到OLED上,y为页地址,x为列地址,fontbuf[]为数据*/
   i+=2;
   x+=16;
}
else if(((text>=0xa1) &&(text<=0xa3))&&(text>=0xa1))
{      
   /*国标简体(GB2312)15x16点的字符在晶联讯字库IC中的地址由以下公式来计算:*/
   /*Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0*/
   /*由于担心8位单片机有乘法溢出问题,所以分三部取地址*/
   fontaddr = (text- 0xa1)*94;
   fontaddr += (text-0xa1);
   fontaddr = (uint32)(fontaddr*32);
   
   addrHigh = (fontaddr&0xff0000)>>16;/*地址的高8位,共24位*/
   addrMid = (fontaddr&0xff00)>>8;      /*地址的中8位,共24位*/
   addrLow = fontaddr&0xff;      /*地址的低8位,共24位*/
   get_nbytes_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32 );/*取32个字节的数据,存到"fontbuf"*/
   display_graphic_16x16(y,x,fontbuf);/*显示汉字到OLED上,y为页地址,x为列地址,fontbuf[]为数据*/
   i+=2;
   x+=16;
}
else if((text>=0x20) &&(text<=0x7e))
{      
   uint08 fontbuf;   
   fontaddr = (text- 0x20);
   fontaddr = (uint32)(fontaddr*16);
   fontaddr = (uint32)(fontaddr+0x3cf80);   
   addrHigh = (fontaddr&0xff0000)>>16;
   addrMid = (fontaddr&0xff00)>>8;
   addrLow = fontaddr&0xff;
   get_nbytes_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,16 );/*取16个字节的数据,存到"fontbuf"*/
   /*显示8x16的ASCII字到LCD上,y为页地址,x为列地址,fontbuf[]为数据*/
   display_graphic_8x16(y,x,fontbuf);
   
   i+=1;
   x+=8;
}
else
   i++;
}

}
//===============================================================
void display_string_5x7(uint08 y,uint08 x,uint08 *text)
{
uint08 i= 0;
uint08 addrHigh,addrMid,addrLow ;
while((text>0x00))
{

if((text>=0x20) &&(text<=0x7e))
{      
   uint08 fontbuf;   
   fontaddr = (text- 0x20);
   fontaddr = (uint32)(fontaddr*8);
   fontaddr = (uint32)(fontaddr+0x3bfc0);   
   addrHigh = (fontaddr&0xff0000)>>16;
   addrMid = (fontaddr&0xff00)>>8;
   addrLow = fontaddr&0xff;
   get_nbytes_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,8);/*取8个字节的数据,存到"fontbuf"*/
   
   display_graphic_5x7(y,x,fontbuf);/*显示5x7的ASCII字到LCD上,y为页地址,x为列地址,fontbuf[]为数据*/
   i+=1;
   x+=6;
}
else
i++;
}

}
//===============主函数===================
void main(void)
{
CLI();                                             //中断禁用
Init_Clock();
Init_Port();
Init_Timer0();
SPI_Init_M0();                                     //SPI初始化时钟格式3
Initial_oled();
//SEI();                                           //中断使能

CS2H;
CS1L;
_NOP();
Fill_screen(0xff);                                 //全部填充
delayms(1000);
Fill_screen(0);                                    //清屏
delayms(100);
while(1)
{

display_128x64(bmp1);                           //显示图片
delayms(2000);
Fill_screen(0);   
display_graphic_16x16(0,1,jiong1);       //在第1行,第1列显示单个自编生僻汉字“囧”
delayms(4000);   
Fill_screen(0);

display_GB2312_string(0,1,"12864,带中文字库"); //在第1页,第1列,显示一串16x16点阵汉字或8x16的ASCII字
display_GB2312_string(2,1,"16X16简体汉字库,");//显示一串16x16点阵汉字或8x16的ASCII字.以下雷同
display_GB2312_string(4,1,"或8X16点阵ASCII,");
display_GB2312_string(6,1,"或5X7点阵ASCII码");   
delayms(2000);   
Fill_screen(0);
   
display_GB2312_string(0,1,"</]!@#$%^&*()_-+]/"); //在第1页,第1列,显示一串16x16点阵汉字或8*16的ASCII字
display_string_5x7(3,1,"</;.,?[]!@#$%^&*()_-+]/;.,?[");//在第3页,第1列,显示一串5x7点阵的ASCII字
display_string_5x7(4,1,"XY electronics Co., "); //显示一串5x7点阵的ASCII字
display_string_5x7(5,1,"Ltd. established at");//显示一串5x7点阵的ASCII字
display_string_5x7(6,1,"year 2016.Focus OLED ");//显示一串5x7点阵的ASCII字
display_string_5x7(7,1,"Edit By xiaoguai");   //显示一串5x7点阵的ASCII字
display_string_5x7(8,1,"You Can learn it");   //显示一串5x7点阵的ASCII字
delayms(2000);
display_GB2312_string(0,1,"啊阿埃挨哎唉哀皑"); //在第1页,第1列,显示一串16x16点阵汉字或8x16的ASCII字
display_GB2312_string(2,1,"癌蔼矮艾碍爱隘鞍");//显示一串16x16点阵汉字或8x16的ASCII字.以下雷同
display_GB2312_string(4,1,"氨安俺按暗岸胺案");
display_GB2312_string(6,1,"肮昂盎凹敖熬翱袄");         
delayms(2000);
display_GB2312_string(0,1,"鬟鬣麽麾縻麂麇麈");
display_GB2312_string(2,1,"麋麒鏖麝麟黛黜黝");
display_GB2312_string(4,1,"黠黟黢黩黧黥黪黯");
display_GB2312_string(6,1,"鼢鼬鼯鼹鼷鼽鼾齄");         
delayms(2000);
   
}

}

初始化文件init.c
/**************************************************************
*************************************************************/
#include<iom328pv.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)
}
//-----------------------------------------------------------------------
void Init_Port(void)
{ DDRB   = BIT(DDB2)|BIT(DDB1);            //PB2 PB1作为片选输出
DDRC|= 0x01;                           //DC输出
PORTB=0xff;
PORTB=0xff;
}
//初始化定时器------------------------------------------------------------
void Init_Timer0(void)
{ //PRR =0b01001101;      //TC1,2抑制,SPI,adc抑制,page34,功耗抑制寄存器
TCCR0A= 0x00;          //正常模式
TCCR0B= 0x04;          //预分频器256分频,每次计数32us,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<<DDB3)|(1<<DDB5);      //设置MOSI 和SCK 为输出,其他为输入
SPCR = 0b01010001;                     //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}
//SPI主机初始化,低速模式125k==========================================================
void SPI_Init_M3(void)
{                                     //SPI模式3
DDRB|= (1<<DDB3)|(1<<DDB5);      //设置MOSI 和SCK 为输出,其他为输入
SPCR = 0b01011001;                     //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}


头文件包含的文件main.h
#ifndef MAIN_H
#define MAIN_H
//数据类型宏定义
typedef unsigned char uint08;
typedef signed   char sint08;
typedef unsigned intuint16;
typedef signed   intsint16;
typedef unsigned long uint32;
typedef const unsigned char cuint08;

//以下是函数声明
void Init_Clock(void);
void Init_Port(void);
void Init_Timer0(void);
void SPI_High_Rate(void);
void SPI_Init_M3(void);
void SPI_Init_M0(void);
#endif

头文件包含的文件数组 picturetable.h
unsigned char const bmp1[]={
//--调入了一幅图像:
//--宽度x高度=128x64--
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x00,0x00,0x00,0xC0,0xA0,
0xE0,0xF0,0xF8,0xB8,0xF8,0xF8,
0xF8,0xF4,0xFC,0xF8,0xF4,0xFC,
0xFC,0xD8,0xFC,0xF8,0xE8,0xF8,
0xF8,0xF0,0xB0,0xE0,0xE0,0xC0,
0xC0,0x80,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x00,0x00,0x20,0x44,0x00,
0x00,0x02,0x00,0x00,0xEC,0xFE,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x9F,0x07,0x07,0x01,0x03,0x00,
0x01,0x01,0x01,0x03,0x03,0x07,
0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFB,
0xFE,0xFC,0xF8,0xF0,0xC0,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x14,0x00,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x13,0x1F,0x7F,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xF8,0xF0,0xE0,
0xE0,0xE0,0xC0,0xE0,0xE0,0xE0,
0xF0,0xF8,0xFE,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x7F,0xFF,0xFE,0xFC,0xE0,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x04,0x51,0x04,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,
0x03,0x03,0x07,0x0F,0x1F,0x1F,
0x1F,0x3F,0x1F,0x3F,0x3F,0x3F,
0x3F,0x3F,0x3F,0x3F,0x7F,0x7F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0xD6,0x24,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x50,0x04,0x90,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x80,0x80,0xC0,
0xC0,0xC0,0xC0,0x80,0x80,0x00,
0x00,0x00,0x00,0x01,0x03,0x03,
0x0F,0x3F,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xBE,0x6B,0x1F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x02,0x00,0x54,0x00,0x40,
0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x54,0xFE,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFE,0x2C,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
0x3F,0x2B,0x1F,0x01,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x05,0x00,0x0A,0x00,
0x08,0x10,0x00,0xA0,0x00,0x00,
0x40,0x80,0x00,0x80,0x00,0x00,
0x01,0x41,0x03,0x03,0x07,0x03,
0x03,0x01,0x03,0x00,0x80,0x00,
0x00,0x40,0x80,0xA0,0x60,0x58,
0x3F,0x1F,0x25,0x1F,0x02,0x07,
0x00,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x01,0x00,
0x00,0x01,0x00,0x01,0x00,0x00,
0x00,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};

kissbaby365 发表于 2016-3-25 16:14

老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么

希岩 发表于 2016-4-5 20:39

kissbaby365 发表于 2016-3-25 16:14
老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么

2.2的tft ili9341?没写过

hdivy 发表于 2016-4-22 15:15

很棒,学习了。。。。

希岩 发表于 2016-5-4 16:12

kissbaby365 发表于 2016-3-25 16:14
老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么

tft的没写过,不好意思

希岩 发表于 2016-5-4 16:13

hdivy 发表于 2016-4-22 15:15
很棒,学习了。。。。

谢谢支持

pxye8888 发表于 2016-6-19 23:09

好文章!赞!赞!赞!
我刚好有他的屏, 还不会读 字库,
现在的问题是, 我只会用Arduino IDE ,老师能把它 搞成   Arduino IDE 能编译的 程序吗? 诚心期待

希岩 发表于 2016-6-30 19:36

pxye8888 发表于 2016-6-19 23:09
好文章!赞!赞!赞!
我刚好有他的屏, 还不会读 字库,
现在的问题是, 我只会用Arduino IDE ,老师能 ...

谢谢啦!这个是用C语言写的,采用了AVRDEF 的头文件,而这个在Aduino IDE下都有,Arduino采用的是C++语言,兼容C语言的,你可以将这个拷过去做一些修改

希岩 发表于 2016-6-30 19:39

希岩 发表于 2016-6-30 19:36
谢谢啦!这个是用C语言写的,采用了AVRDEF 的头文件,而这个在Aduino IDE下都有,Arduino采用的是C++语言 ...

给你一个简化版的读字库的程序,原本在ICCAVR编译的,你可以转成Arduino的
/****************************************************************************       
//!!本程序只供学习使用,未经作者许可,不得用于其它任何用途
//参    考   :中景园电子
//作    者   : XiaoGuai
//生成日期   : 2016-0318
//功能描述   : 字库版 OLED SPI接口演示例程(Atmega328系列)
//说    明:
               OLED驱动芯片: SSH1106
               单片机:      ATMEGA328P-PU
               晶振:      片外16Mhz石英晶振
               工作频率:    8Mhz
//========================以下为OLED显示所用到的接口===========================
//            GND       电源地
//            VCC       接5V或3.3v电源
//            CLK       PB5
//            MOSI      PB3
//            DC      PC0
//            CS1       PB2OLED片选
//            FSO       PB4MISO
//            CS2       PB1字库片选            

********************************************************************************/
#include<iom328pv.h>
#include<AVRdef.h>
#include "main.h"


#define CS1LPORTB&=0xfb      //CS1低
#define CS1HPORTB|=0x04      //CS1高
#define CS2LPORTB&=0xfd      //CS2低
#define CS2HPORTB|=0x02      //CS2高
                                  
const uint08 table[]={"繁华怅落三月天,烟雨清荷难落墨。莺鸣柳前花未开,渡岸湖中又初雪。一个人的长街莲灯,一个人的沽桥寻梦;回忆是最饥饿的渴望,难以伪装的是那离别时脸颊清澈的悲伤。被放逐的路途是没有归航的流浪,提笔落下一袭的水墨烟云;且说着情深却恨着缘浅,等不到的是故梦的重圆;可我却等来了一场桃花未央中的嫣然雨落,如果这就是爱情最初的颜色;那么我愿为你在这场烟雨中画下天涯的海角。可你是否曾知晓过?当一场烟雨落尽满树的繁花时,这注定又会是一场花开花落间的寂寥。"};
//延时函数======================================================================
void delayms(uint16 u16count)
{uint16 count,i;
for(i=0;i<u16count;i++)
{count=TCNT0;                     //读取计数器0
   while((TCNT0-count)<32)WDR();      //每次约1ms
}
}

//SPI数据传输,采用轮询=========================================================
uint08 SPI_Tran_Byte(uint08 data)
{
SPDR = data;                              //启动数据传输
while(!(SPSR & (1<<SPIF)));               //等待传输结束
return SPDR;                                                         //接收字符
}

//写指令到oled模块==============================================================
void tran_cmd_oled(uint08 data)   
{
PORTC&=0xfe;       //DC=0 PC0=0
_NOP();       
(void)SPI_Tran_Byte(data);
}

//写数据到oled模块==============================================================
void tran_dat_oled(uint08 data)   
{
PORTC|=0x01;       //DC=1 PC0=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[],uint16 StrAdd)
{   uint32 fontadd=0;                     //32位数据地址
        uint08 addrHigh,addrMid,addrLow ;
        uint08 fontbuf;       
                       
        while(ch)                     //数据值不为0
        {
                if((ch>175)&&(ch<248)&&(ch>160))
                {                                               
                                                              //国标简体(GB2312)汉字在晶联讯字库IC中的地址由以下公式来计算:
                                                              //Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0
                                                              //由于担心8位单片机有乘法溢出问题,所以分三部取地址
                        fontadd = (ch-176)*94;
                        fontadd += (ch-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"
                        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 StrAdd;         //返回当前地址
                }
                else if((ch>160)&&(ch<164)&&(ch>160))
                {                                               
                                                                 //Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0
                        fontadd = (ch- 0xa1)*94;
                        fontadd += (ch-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 StrAdd;       //返回当前地址
                }
                else if((ch>31)&&(ch<127))       
                {                                               
                        fontadd = ch- 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 StrAdd;          //返回当前地址
                }

        }
        return 0;
       
}

//===============主函数===================
void main(void)
{   uint16 add=0;
        CLI();                                             //中断禁用
        Init_Clock();
        Init_Port();
        Init_Timer0();
        SPI_Init_M0();                                     //SPI初始化时钟格式3       
        Initial_oled();       
        //SEI();                                           //中断使能
       
        CS2H;
    CS1L;
    _NOP();
        Fill_screen(0xff);                                 //全屏填充
        delayms(500);
        Fill_screen(0);                                    //清屏
        delayms(100);                                                                                          
       
               

                             
        while(1)
        { WDR();
          add=0;
          do{
          add=Dis_GB2312_Str(0,1,table,add);         //在第1行,第1列,显示表中的数据
          delayms(2000);
          Fill_screen(0);                                    //清屏
          } while(add);
        }
       
}

//以下是Init。c文件
/**************************************************************
*************************************************************/

#include<iom328pv.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)
}

//-----------------------------------------------------------------------
void Init_Port(void)
{ DDRB   = BIT(DDB2)|BIT(DDB1);            //PB2 PB1作为片选输出
DDRC|= 0x01;                           //DC输出
PORTB=0xff;
PORTB=0xff;
}
//初始化定时器------------------------------------------------------------
void Init_Timer0(void)
{ PRR =0b01001001;                  //TC1,2抑制,adc抑制,page34,功耗抑制寄存器
TCCR0A= 0x00;          //正常模式
TCCR0B= 0x04;          //预分频器256分频,每次计数32us,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<<DDB3)|(1<<DDB5);      //设置MOSI 和SCK 为输出,其他为输入
SPCR = 0b01010001;                     //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}
//SPI主机初始化,低速模式125k==========================================================
void SPI_Init_M3(void)
{                                     //SPI模式3
DDRB|= (1<<DDB3)|(1<<DDB5);      //设置MOSI 和SCK 为输出,其他为输入
SPCR = 0b01011001;                     //使能SPI 主机模式,时钟模式为下降沿,结束沿采样,设置时钟速率为fck/16
}

小二郎a 发表于 2016-8-14 13:51

你好 我有一个问题 就是看了你的操作带字库的oled帖子时,51例程里面是这样的if( Rom_OUT )
                        ret_data=ret_data+1;
但是在arduino里面,把rom_out设置为输出模式后不是不能读取引脚的高低电平吗,如果把rom_out在设置为输入模式的话会不会影响他的输出高低电平状态? 请问你是怎么解决的呢
页: [1] 2
查看完整版本: ATmega 328驱动SPI模式的OLED屏代码