Oled实现动图显示——篮球少年
Oled显示模块,用char定义清除界面会导致画面屏雪花;如果用char i,j;有符号,表示从-128——127,会导致某些数被吞掉,用int或者unsigned char(表示无符号)
设备:51开发板和0.96寸4针Oled 显示模块。
动图显示说白了就是把GIF图分离成一帧一帧的图片显示一张图片和显示一张图片差不多。
第一步:提取分离图片推荐用Gifsplitter
第二步:降低画质,图片改为是bmp格式,大小调成128×64(可以在软件内部调也可以用Windows画图应用调)具体如下:
第三步:对图片取模(最繁琐的一步,哪里有一键取模软件迫切希望告知)我这里用的是CopyLeft Bu Horse2000,建议使用PCtolCD
取模完成把数组添加到其中具体代码如下:
#include "reg52.h"
#include "intrins.h"
sbit scl = P0^1;
sbit sda = P0^3;
void IIC_Start()
{
scl = 0;
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();
}
void IIC_Stop()
{
scl = 0;
sda = 0;
scl = 1;
_nop_();
sda = 1;
_nop_();
}
char IIC_ACK()
{
char flag;
sda = 1;//就在时钟脉冲9期间释放数据线
_nop_();
scl = 1;
_nop_();
flag = sda;
_nop_();
scl = 0;
_nop_();
return flag;
}
void IIC_Send_Byte(char dataSend)
{
int i;
for(i = 0; i<8; i++) {
scl = 0;//scl拉低,让sda做好数据准备
sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
_nop_();//发送数据建立时间
scl = 1;//scl拉高开始发送
_nop_();//数据发送时间
scl = 0;//发送完毕拉低
_nop_();//
dataSend = dataSend << 1;
}
}
void Oled_Write_Cmd(char dataCmd)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
IIC_Send_Byte(0x00);
// 5. ACK
IIC_ACK();
//6. 写入指令/数据
IIC_Send_Byte(dataCmd);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
void Oled_Write_Data(char dataData)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
IIC_Send_Byte(0x78);
// 3. ACK
IIC_ACK();
// 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
IIC_Send_Byte(0x40);
// 5. ACK
IIC_ACK();
///6. 写入指令/数据
IIC_Send_Byte(dataData);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}
void Oled_Init(void) {
Oled_Write_Cmd(0xAE);//--display off
Oled_Write_Cmd(0x00);//---set low column address
Oled_Write_Cmd(0x10);//---set high column address
Oled_Write_Cmd(0x40);//--set start line address
Oled_Write_Cmd(0xB0);//--set page address
Oled_Write_Cmd(0x81); // contract control
Oled_Write_Cmd(0xFF);//--128
Oled_Write_Cmd(0xA1);//set segment remap
Oled_Write_Cmd(0xA6);//--normal / reverse
Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
Oled_Write_Cmd(0x3F);//--1/32 duty
Oled_Write_Cmd(0xC8);//Com scan direction
Oled_Write_Cmd(0xD3);//-set display offset
Oled_Write_Cmd(0x00);//
Oled_Write_Cmd(0xD5);//set osc division
Oled_Write_Cmd(0x80);//
Oled_Write_Cmd(0xD8);//set area color mode off
Oled_Write_Cmd(0x05);//
Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
Oled_Write_Cmd(0xF1);//
Oled_Write_Cmd(0xDA);//set com pin configuartion
Oled_Write_Cmd(0x12);//
Oled_Write_Cmd(0xDB);//set Vcomh
Oled_Write_Cmd(0x30);//
Oled_Write_Cmd(0x8D);//set charge pump enable
Oled_Write_Cmd(0x14);//
Oled_Write_Cmd(0xAF);//--turn on oled panel
}
void Oled_Clear(void) {
int i,j;
Oled_Write_Cmd (0x20); //set memory addressing mode
Oled_Write_Cmd (0x02); //page addressing mode
for(i=0; i<8; i++) {
Oled_Write_Cmd(0xB0+i); //ÉèÖÃÒ³µØÖ·£¨0~7£©
Oled_Write_Cmd(0x00); //ÉèÖÃÏÔʾλÖáªÁе͵ØÖ·
Oled_Write_Cmd(0x10); //ÉèÖÃÏÔʾλÖáªÁиߵØÖ·
for(j=0; j<128; j++) {
Oled_Write_Data(0);
}
}
}
void Oled_Show_Image(unsigned char *image) {
unsigned char i;
unsigned int j;
for(i=0; i<8; i++) {
Oled_Write_Cmd(0xB0+i); //page0 ——page7
Oled_Write_Cmd(0x00); //每个page从第0列开始
Oled_Write_Cmd(0x10);
for(j=128*i; j<128*(i+1); j++) {
Oled_Write_Data(image[j]);
}
}
}
void main()
{
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
//Oled_Show_Image(bmpImager);
while(1) {//取模代码太多就不写出来了
Oled_Show_Image(bmpImager41);
_nop_();
Oled_Show_Image(bmpImager42);
_nop_();
Oled_Show_Image(bmpImager43);
_nop_();
Oled_Show_Image(bmpImager44);
_nop_();
Oled_Show_Image(bmpImager45);
_nop_();
Oled_Show_Image(bmpImager46);
_nop_();
}
}
这个代码会使Oled显示帧率有点问题,应该是延时函数过多,代码冗余或是其他问题,欢迎交流解决。
效果演示
学习