咣铛咣铛~~~~~~~~~~~~~~~开课了.
这一季,我们来学习OLED,为啥要先搞OLED呢,因为学习的时候通常调试程式的时候要看结果,当然用篇程器来模拟也是一种办法,但我觉得
太慢了,一上机就执行多好.所以偶通常很少用篇程器.所以我设计的板子单片机富余的脚全接一个小灯.主要是调程式用的和迷惑客户用的.
因为灯闪起来很科幻的感觉 ^_^Y
好,首先,我们要搞明白这个屏的第一点在那个地方,现在我们定义,排线所在的地方是下.看一下第一页在那个地方.
在写代码之前,我们看原子的书是明白了如下几点:
1. 这个屏分8页,每页有128列LED小灯,每列有8个小灯.
2.每一个列用一个8位的二进制的数来控制小灯,每一个小灯对应一个位. 如位上是1,那就是点亮这个灯,如位上是0,那就是来灭掉这个灯.
3.在写进每一列的时候,都要输入 页地址 和 列 地址.
如我们要写 0x01 进第0页,第一列.那代码是这样表示的:
OLED_WR_Byte (0xb0,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
OLED_WR_Byte()是一个函数,等一下我们会写,先不理.看上边.b0表示第一页,如此类推,b1,b2,b3........b7表示第2页到8页.
例地址分两次丢进OLED.第一次丢低位4位,第二次丢高4位.为了在命令上全高底位,在两次地址数中的第五位是0表示丢的是底4位,如果是1则是
丢的是高4位.5,6,7位没有用,所以全是0. 我们的做法是,第要丢进去的列地址砍成两半,低4位加上4个0做高4位真接丢进去,高4位右移4位再在第
5位或运算一个1真接丢进去,就OK了.(PS: 原子老大的书(我买的是第一版)第139面的表格是有误的,最后一行的Bit5应是1,不是0)
好我们要写的代码用意是 显示一个点在第0页的第一列最底下显示.然后住上走,又从第二页的第一列的最底显示然后也是住上走,如此类推,一直显
示到第8页的第一列的最顶上,就象一个子弹从地上往上打,一打到顶上.然后回到第一页,列地址加1,然后重复上边的动作,子弹一直打到128列.
好,代码如下:
先写个头,将要将默认的东东写上.
#include "sys.h"
#include "usart.h"
#include "delay.h"
#define OLED_CS PCout(9)
//#define OLED_RST    Bout(14)//在MINISTM32上直接接到了STM32的复位脚!
#define OLED_RS PCout(8)
#define OLED_WR PCout(7)
#define OLED_RD PCout(6)
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
//PB0~7,作为数据线
#define DATAOUT(x) GPIOB->ODR=(GPIOB->ODR&0xff00)|(x&0x00FF); //输出
然后写设一个数组,是第二季用的.主要是在内存里画好画,再刷到屏里去的.这季先不用.
u8 OLED_GRAM[128][8];
再然后是IO设置,跟据电路图我们设置代码如下  秒原子哥的来用就行了,OLED初始化不用理它,厂家给的,直接丢进去就行)
void IO_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
RCC->APB2ENR|=1<<4; //使能PORTC时钟
JTAG_Set(SWD_ENABLE);
GPIOB->CRL=0X33333333;
GPIOB->ODR|=0XFFFF;
GPIOC->CRH&=0XFFFFFF00;
GPIOC->CRL&=0X00FFFFFF;
GPIOC->CRH|=0X00000033;
GPIOC->CRL|=0X33000000;
GPIOC->ODR|=0X03C0;
OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD); //默认为0
OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.
OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置
OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD); //开启显示
OLED_Clear();
}
然后是将数字丢进OLED的代码. 这要注意一点,原子老大的板子是并行的,所以写入数据是用8080并口模式.不是SPI模式.SPI模式我们最后一季试.因为要动电铬铁.麻烦,先不搞.
void OLED_WR_Byte(u8 dat,u8 cmd)
{
DATAOUT(dat);
OLED_RS=cmd;
OLED_CS=0;
OLED_WR=0;
OLED_WR=1;
OLED_CS=1;
OLED_RS=1;
}
然后是从内存将数据对应地刷到OLED内存里去.这一季可以不管.
void OLED_Refresh_Gram(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n],OLED_DATA);
}
}
然后是清屏函数,这一季也可以不理.
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)for(n=0;n<128;n++)OLED_GRAM[n]=0X00;
OLED_Refresh_Gram();//更新显示
}
然后是主函数:
int main(void)
{
u8 i,j,k,l,m,o,textdata=1;
Stm32_Clock_Init(9);
delay_init(72);
uart_init(72,9600);
IO_Init();
while(1)
{
for (i=0;i<128;i++)
{
k=i&0x0f;
l=(i>>4)|0x10;
for(j=0;j<8;j++)
{
for (o=0;o<9;o++) //主要是最后一次写的是0x00.要不然第8次循环就是0x80了,顶上会有一点.
{
OLED_WR_Byte (0xb0+m,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (k,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (l,OLED_CMD); //设置显示位置—列高地址
OLED_WR_Byte (textdata,OLED_DATA);
textdata<<=1;
delay_ms(10);
}
textdata=1;
m=m+1;
if (m==7)m=0;
}
}
}
}
将上边的所有代码编译好后丢进学习板,看到没~~~~~~~~~~~~~~~~子弹在飞~~~~~~~~~~~~~~~~~~~
好了,我们得出OLED的第一页在最下边一行,依次住上,黄色那行是第8页.最左边是第一列.每一列的数字是高位在上,底位在下边.最低下那个是0位.
这样我们就明白OLED的显示方式了.
最后,我们再来搞搞新意思
int main(void)
{
u8 i,j,k,l,m,o,n,textdata=1;
Stm32_Clock_Init(9);
delay_init(72);
uart_init(72,9600);
IO_Init();
while(1)
{
for (i=0;i<128;i++)
{
k=i&0x0f;
l=(i>>4)|0x10;
for(j=0;j<8;j++)
{
for (o=0;o<9;o++)
{
OLED_WR_Byte (0xb0+m,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (k,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (l,OLED_CMD); //设置显示位置—列高地址
OLED_WR_Byte (textdata,OLED_DATA);
textdata=0xff;
// delay_ms(10);
}
textdata=1;
m=m+1;
if (m==7)m=0;
}
}
for(n=0;n<200;n++)
{
OLED_WR_Byte (0x81,OLED_CMD);
OLED_WR_Byte (n,OLED_CMD);
delay_ms(10);
}
for(n=200;n>0;n--)
{
OLED_WR_Byte (0x81,OLED_CMD);
OLED_WR_Byte (n,OLED_CMD);
delay_ms(10);
}
呼吸灯~~~~~~~~~~~~~~~ |