OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10333|回复: 11

学习ARM笔记 OLED 第一季

[复制链接]

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
发表于 2012-6-16 04:36:45 | 显示全部楼层 |阅读模式
 咣铛咣铛~~~~~~~~~~~~~~~开课了.

这一季,我们来学习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);
    }

呼吸灯~~~~~~~~~~~~~~~
我的工作就是天天在玩
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

68

帖子

0

精华

初级会员

Rank: 2

积分
152
金钱
152
注册时间
2012-3-21
在线时间
5 小时
发表于 2012-6-16 09:58:26 | 显示全部楼层
回复【楼主位】chinafox:
---------------------------------
顶起来~~~~
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-6-16 10:38:21 | 显示全部楼层
确实BIT4应该是1...原先的有误.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

16

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2012-7-11
在线时间
0 小时
发表于 2013-1-22 10:31:32 | 显示全部楼层
回复【楼主位】chinafox:
---------------------------------
灰常完美  感谢楼主
回复 支持 反对

使用道具 举报

0

主题

15

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2012-9-20
在线时间
0 小时
发表于 2013-1-25 16:47:45 | 显示全部楼层
LZ-_-我想请教哈  OLED_WR_Byte (k,OLED_CMD);      //设置显示位置—列低地址
                 OLED_WR_Byte (l,OLED_CMD);      //设置显示位置—列高地址 
这两句代码写的具体含义是怎么样的呢?做为列地址的话,一般是0x00,0x10就可以的,只是我试了 也不行。而且这两句跟所显示的列的位置是什么样的关系啊
回复 支持 反对

使用道具 举报

46

主题

1579

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1970
金钱
1970
注册时间
2011-7-17
在线时间
4 小时
发表于 2013-1-26 10:43:25 | 显示全部楼层
顶,季度都出来了
Time?And?Relative?Dimension?In?Space.
回复 支持 反对

使用道具 举报

27

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
387
金钱
387
注册时间
2014-8-19
在线时间
0 小时
发表于 2014-9-21 17:23:41 | 显示全部楼层
楼主在不在?
回复 支持 反对

使用道具 举报

27

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
387
金钱
387
注册时间
2014-8-19
在线时间
0 小时
发表于 2014-9-21 17:30:28 | 显示全部楼层
好了,我们得出OLED的第一页在最下边一行,依次住上,黄色那行是第8页.最左边是第一列.每一列的数字是高位在上,底位在下边.最低下那个是0位.
这样我们就明白OLED的显示方式了.

得出这个结论有意义吗?显示方式是可以设置的,我现在用的OLED,就是第页在第上面。依次向下,最左边是第一列,每列上面是低位,下面是高位。
回复 支持 反对

使用道具 举报

27

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
387
金钱
387
注册时间
2014-8-19
在线时间
0 小时
发表于 2014-9-21 17:33:55 | 显示全部楼层
回复【5楼】442609298:
---------------------------------
在吗?我也是看不懂
回复 支持 反对

使用道具 举报

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
 楼主| 发表于 2014-9-27 19:26:45 | 显示全部楼层
各位老大,先找到第一列第一行的那个点你就能爱咋就咋地了,代码要自己写,看人家的时间你自己都能写出一个来了,看人家的代码只是验证一下自己的想法有没有错的而已。反正我不习惯使用抄人家的例程,只是一边看说明书一边看人家的例程,理解后自己写一个,到时要什么改都行,必竟是自己写的嘛。
我的工作就是天天在玩
回复 支持 反对

使用道具 举报

18

主题

139

帖子

0

精华

高级会员

Rank: 4

积分
560
金钱
560
注册时间
2014-10-29
在线时间
228 小时
发表于 2015-1-11 20:15:15 | 显示全部楼层
怎么把这个程序下载到战舰开发板上一点反应没有??
回复 支持 反对

使用道具 举报

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
 楼主| 发表于 2015-1-12 15:45:54 | 显示全部楼层
原子的战舰板子我还没开封................常用他的MINI板子开发,从第一块到现在,我自己和客户已经买了40多块MINI板了。
我的工作就是天天在玩
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-27 05:25

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表