注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
crystal008的个人空间 https://home.eeworld.com.cn/space-uid-598534.html [收藏] [复制] [分享] [RSS]
日志

STM32经四线SPI与OLED通信

热度 1已有 22098 次阅读2015-3-27 11:37 | 通信

在大多数STM32的OLED驱动例程中,都给出了相关的软件驱动和硬件设计方法,对具体SSD1306的接线以及IO口的初始化未给出详细的说明。可能是我水平有限,未看明白;或者是大师们不屑说这些简单的内容。以下是自己在做OLED驱动的代码和说明,对初次实验者可能有些帮助。

OLED.H文件

#include "oled.h"
#include "stdlib.h"
#include "sys.h"    
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//STM32开发板
//SSD1306 OLED 驱动代码
//驱动方式:4线SPI串口
//版权所有,盗版必究。
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////   

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C   

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

//接线方式如下:当然,VCC和GND必须连接,VCC建议连接3.3V

#define LCD_SCL PBout(8)    //时钟 D0(SCLK)  
#define LCD_SDA PBout(9)    //D1(SDA) 数据
#define LCD_RST PDout(6)    //复位RST 
#define LCD_DC  PBout(5)    //DC数据/命令控制

extern void LCD_DLY_ms(unsigned int ms);
extern void LCD_WrDat(unsigned char dat);
extern void LCD_Set_Pos(unsigned char x, unsigned char y);
extern void LCD_Fill(unsigned char bmp_dat);
extern void LCD_CLS(void);
extern void LCD_P6x8Str(unsigned char x,unsigned char  y,unsigned char ch[]);
extern void LCD_P8x16Str(unsigned char x,unsigned char  y,unsigned char ch[]);
extern void LCD_P16x16Ch(unsigned char x,unsigned char  y,unsigned char  N);
extern void Draw_BMP(unsigned char x0,unsigned char  y0,unsigned char x1,unsigned char  y1,unsigned char BMP[]);
extern void OLED_Init(void);

OLED.C文件
#define XLevelL  0x00
#define XLevelH  0x10
#define XLevel     ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column 128
#define Max_Row  64
#define Brightness 0xCF 
#define X_WIDTH 128
#define Y_WIDTH 64
/*********************LCD 延时1ms************************************/
void LCD_DLY_ms(unsigned int ms)
{                         
      unsigned int a;
      while(ms)
      {
            a=1800;
            while(a--);
                  ms--;
      }
}
/*********************LCD写数据************************************/ 
void LCD_WrDat(unsigned char dat)  
{
      unsigned char i=8;
      LCD_DC=1;  
      for(i=0;i<8;i++) //发送一个八位数据 
     { 
            LCD_SCL=0; 
            if(dat&0x80) LCD_SDA=1;
            else LCD_SDA=0;
             LCD_SCL=1;             
            dat<<=1;    
     }
}
/*********************LCD写命令************************************/          
void LCD_WrCmd(unsigned char cmd)
{
           unsigned char i=8;
           LCD_DC=0;
           for(i=0;i<8;i++) //发送一个八位数据 
          {  
                 LCD_SCL=0; 
                 if(cmd&0x80)LCD_SDA=1;
                 else LCD_SDA=0;
                 LCD_SCL=1;  
                 cmd<<=1;;   
          } 
          LCD_DC = 1; 
}
/*********************LCD 设置坐标************************************/
void LCD_Set_Pos(unsigned char x, unsigned char y) 
{ 
       LCD_WrCmd(0xb0+y);
       LCD_WrCmd(((x&0xf0)>>4)|0x10);
       LCD_WrCmd((x&0x0f)|0x01); 
} 
/*********************LCD全屏************************************/
void LCD_Fill(unsigned char bmp_dat) 
{
          unsigned char y,x;
          for(y=0;y<8;y++)
         {
                 LCD_WrCmd(0xb0+y);
                 LCD_WrCmd(0x01);
                 LCD_WrCmd(0x10);
                 for(x=0;x<X_WIDTH;x++)
                {
                         LCD_WrDat(bmp_dat);
                }
          }
}
/*********************LCD复位************************************/
void LCD_CLS(void)
{
          unsigned char y,x; 
          for(y=0;y<8;y++)
         {
                LCD_WrCmd(0xb0+y);
                LCD_WrCmd(0x01);
                LCD_WrCmd(0x10); 
                for(x=0;x<X_WIDTH;x++)
                     LCD_WrDat(0);
          }
}
/***************功能描述:显示6*8一组标准ASCII字符串 显示的坐标(x,y),y为页范围0~7****************/
void LCD_P6x8Str(unsigned char x,unsigned char  y,unsigned char ch[])
{
         unsigned char c=0,i=0,j=0;      
         while (ch[j]!='\0')
         {    
                 c =ch[j]-32;

                 if(x>126){x=0;y++;}
                        LCD_Set_Pos(x,y);    
                 for(i=0;i<6;i++)     
                        LCD_WrDat(F6x8[c][i]);  
                 x+=6;
                 j++;
}
}
/*******************功能描述:显示8*16一组标准ASCII字符串  显示的坐标(x,y),y为页范围0~7****************/
void LCD_P8x16Str(unsigned char x,unsigned char  y,unsigned char ch[])
{
         unsigned char c=0,i=0,j=0;
         while (ch[j]!='\0')
         {    
                c =ch[j]-32;
                if(x>120){x=0;y++;}
                          LCD_Set_Pos(x,y);    
                for(i=0;i<8;i++)     
                          LCD_WrDat(F8X16[c*16+i]);
                LCD_Set_Pos(x,y+1);    
                for(i=0;i<8;i++)     
                           LCD_WrDat(F8X16[c*16+i+8]);  
                x+=8;
                j++;
           }
}
/*****************功能描述:显示16*16点阵  显示的坐标(x,y),y为页范围0~7****************************/
void LCD_P16x16Ch(unsigned char x,unsigned char  y,unsigned char  N)
{
        unsigned char wm=0;
        unsigned int adder=32*N;  //   
        LCD_Set_Pos(x , y);
        for(wm = 0;wm < 16;wm++)  //             
       {
                 LCD_WrDat(F16x16[adder]);
                 adder += 1;
        }      
        LCD_Set_Pos(x,y + 1); 
        for(wm = 0;wm < 16;wm++) //         
       {
                 LCD_WrDat(F16x16[adder]);
                 adder += 1;
        }     
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void Draw_BMP(unsigned char x0,unsigned char  y0,unsigned char x1,unsigned char  y1,unsigned char BMP[])
{  
         unsigned int j=0;
         unsigned char x,y;
         if(y1%8==0) y=y1/8;      
         else y=y1/8+1;
         for(y=y0;y<y1;y++)
         {
                 LCD_Set_Pos(x0,y);    
                 for(x=x0;x<x1;x++)
                 {      
                            LCD_WrDat(BMP[j++]);      
                 }
           }
}  
    
//初始化SSD1306         
void OLED_Init(void)
{                   
            GPIO_InitTypeDef  GPIO_InitStructure;     
            RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD, ENABLE );
    
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //推挽输出   SCLK - PB8  SDIN - PB9
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;     //这个频率不能太高,10M我试过,OLED屏显示会有问题
            GPIO_Init(GPIOB, &GPIO_InitStructure);

             GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                    //       DC - PB5
             GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;    //推挽输出 
             GPIO_Init(GPIOB, &GPIO_InitStructure); 
                                                                                                 //               RST - PD6
             GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
             GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
             GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
             GPIO_Init(GPIOD, &GPIO_InitStructure);
             GPIO_SetBits(GPIOD, GPIO_Pin_6);

              LCD_SCL=1;
              LCD_RST=0;
              LCD_DLY_ms(50);
              LCD_RST=1;       //从上电到下面开始初始化要有足够的时间,即等待RC复位完毕   
              LCD_WrCmd(0xae);//--turn off oled panel
              LCD_WrCmd(0x00);//---set low column address
              LCD_WrCmd(0x10);//---set high column address
              LCD_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
              LCD_WrCmd(0x81);//--set contrast control register
              LCD_WrCmd(0xcf); // Set SEG Output Current Brightness
              LCD_WrCmd(0xa1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
              LCD_WrCmd(0xc8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
              LCD_WrCmd(0xa6);//--set normal display
              LCD_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
              LCD_WrCmd(0x3f);//--1/64 duty
              LCD_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
              LCD_WrCmd(0x00);//-not offset
              LCD_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
              LCD_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
              LCD_WrCmd(0xd9);//--set pre-charge period
              LCD_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
              LCD_WrCmd(0xda);//--set com pins hardware configuration
              LCD_WrCmd(0x12);
              LCD_WrCmd(0xdb);//--set vcomh
              LCD_WrCmd(0x40);//Set VCOM Deselect Level
              LCD_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
              LCD_WrCmd(0x02);//
              LCD_WrCmd(0x8d);//--set Charge Pump enable/disable
              LCD_WrCmd(0x14);//--set(0x10) disable
              LCD_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
              LCD_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7) 
              LCD_WrCmd(0xaf);//--turn on oled panel
              LCD_Fill(0x00);  //初始清屏
              LCD_Set_Pos(0,0); 
}  

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main(void)
{
       /* Add your application code here*/
       unsigned char i=0;
       LED_GPIO_Config();
       delay_init(72);      //延时初始化
       OLED_Init();   //初始化OLED  

       LCD_P8x16Str(28,0,"OLED TEST");   
       LCD_P8x16Str(20,2,"OLEDDISPLAY");   
       LCD_P6x8Str(16,5,"315322339@qq.com"); 
       LCD_P6x8Str(34,6,"2014-11-22");   

       delay_ms(1000);
       Draw_BMP(0,0,128,8,BMP);  //图片显示
       delay_ms(1500);           //延时1s
       LCD_Fill(0);
       while(1)
       {  
              LED4_OFF;
              delay_ms(1000); //延时1s
              LED4_ON;
              delay_ms(1000); //延时1s
   
               for(i=0; i<8; i++)
               {
                       LCD_P16x16Ch(i*16,0,i);  //点阵显示
                       LCD_P16x16Ch(i*16,2,i+8);
                       LCD_P16x16Ch(i*16,4,i+16);
                       LCD_P16x16Ch(i*16,6,i+24);
                }  
        }
}

发表评论 评论 (1 个评论)
回复 qq973453867 2015-12-17 21:50
main函数调用LED_GPIO_Config();没定义,我用51可以初始化成功,用M3不行。纳闷

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章