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
}; 老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么 kissbaby365 发表于 2016-3-25 16:14
老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么
2.2的tft ili9341?没写过 很棒,学习了。。。。 kissbaby365 发表于 2016-3-25 16:14
老乡 我有个2.2的tft ili9341的,有合适的驱动介绍么
tft的没写过,不好意思 hdivy 发表于 2016-4-22 15:15
很棒,学习了。。。。
谢谢支持
好文章!赞!赞!赞!
我刚好有他的屏, 还不会读 字库,
现在的问题是, 我只会用Arduino IDE ,老师能把它 搞成 Arduino IDE 能编译的 程序吗? 诚心期待 pxye8888 发表于 2016-6-19 23:09
好文章!赞!赞!赞!
我刚好有他的屏, 还不会读 字库,
现在的问题是, 我只会用Arduino IDE ,老师能 ...
谢谢啦!这个是用C语言写的,采用了AVRDEF 的头文件,而这个在Aduino IDE下都有,Arduino采用的是C++语言,兼容C语言的,你可以将这个拷过去做一些修改 希岩 发表于 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
}
你好 我有一个问题 就是看了你的操作带字库的oled帖子时,51例程里面是这样的if( Rom_OUT )
ret_data=ret_data+1;
但是在arduino里面,把rom_out设置为输出模式后不是不能读取引脚的高低电平吗,如果把rom_out在设置为输入模式的话会不会影响他的输出高低电平状态? 请问你是怎么解决的呢
页:
[1]
2