STM32单片机初学5 您所在的位置:网站首页 oled显示时间顺移一位怎么设置 STM32单片机初学5

STM32单片机初学5

2024-07-15 20:33| 来源: 网络整理| 查看: 265

在我上篇文章(STM32-软件模拟IIC通信)讲解了软件模拟IIC通信。这篇文章详将细讲解利用软件模拟IIC来控制0.96寸的OLED屏幕(如下图),使其显示字符串。本文将不再对IIC通信原理做详细讲解,所以对IIC通信原理不熟悉的话可以参考我上篇文章(点击上面的链接直接跳转)。

上面这款屏幕是单片机学习中最常用的产品之一,在很多单片机作品中都能见到,首先简单介绍这款OLED屏幕:

分辨率:64*128(最多可显示8行ASCII字符或者4行汉字)

屏幕尺寸:0.96寸

通信方式:IIC

端口:GND、VCC、SCL、SDA(地、3V-5V供电、IIC时钟线、IIC数据线)

驱动芯片:SSD1306

要使用一款屏幕,先要从其驱动芯片下手。在网上找到其使用手册,一般就知道如何使用。

这里我就简单介绍其工作过程。在SSD1306内部有一片显示SRAM缓存区,每个存储单元的状态正好对应屏幕上像素点的状态(0或者1)。控制芯片按照该SRAM的数据扫描OLED屏幕(动态扫描,其原理可参考文章动态扫描显示原理)。所以单片机只需要通过IIC将数据写进SRAM中,刷新屏幕的事全部交给驱动芯片就可以。与单片机内部的SRAM(静态随机存储器)一样,一旦断电,其数据就会丢失,所以该OLED屏幕断电之后再上电,显示SRAM就是空白的。

---------------------------------------------------------

我们先来了解其屏幕分区。 

 整块屏幕分为8个大区,称之为页(从上到下依次为Page0-到Page7),每一页又分为128列,每一列又分为8个小块。每个小块对应一个像素点,有0与1两种状态(代表像素点的灭与亮),可以用1bit数据来表示。每一列是8个小块,也就是8bit,即1Byte。在IIC数据传输时,正好也是1Byte为一个数据帧,所以发送一次数据正好刷新了SRAM中8个像素点的状态。

在设置OLED的初始坐标时都是通过某页某列进行定位的,定位用的命令下文介绍。

常见的OLED屏幕都是如上图,只有4个引脚,但我这里使用的是7脚的OLED屏,它不仅支持IIC通信,还支持4线SPI、3线SPI。如图

 该OLED出厂默认的是4线SPI,所以如果想用IIC通信,还得改线路(如上图丝印所示),即将R3的4.7K电阻拆下来装在R1的位置上,并将R8短接或者另外找一个0603的4.7K电阻焊上。

其引脚定义如下:

GND:接电源地

VCC:接电源VCC(3V-5V)

D0:IIC-SCL / SPI-CLK。这里接单片机的IIC_SCL

D1:IIC-SDA / MOSI。这里接单片机的IIC-SDA

RES:复位脚。可用一个GPIO来控制

DC:屏幕IIC地址选择线(低电平:地址为0x78;高电平:0x7A),一般直接接地

CS:SPI片选 SPI-CS,这里直接接地

如果是4线的OLED屏,接法则简单多了,与单片机对应连接即可,省去了后面三个引脚,DC在其内部接了地,地址固定为0x78。

其他不多说,一边看程序,一边讲解。

1.头文件及函数声明

这里我把PB10作为IIC的模拟SCL,PB11作为IIC的模拟SDA,PC13作为OLED的复位脚。并对他们的置复位进行声明,方便使用。(之所以这么声明,是因为STM32没有sbit,不能直接将变量映射到引脚)

#include #include #include #define Read_IIC_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) //Read_IIC_SDA读取PB11的值 #define OLED_RES_H() GPIO_SetBits(GPIOC, GPIO_Pin_13) //OLED RES脚置高电平 #define OLED_RES_L() GPIO_ResetBits(GPIOC, GPIO_Pin_13) //OLED RES置低电平 #define IIC_SCL_H() GPIO_SetBits(GPIOB,GPIO_Pin_10) // IIC_SCL置高 #define IIC_SCL_L() GPIO_ResetBits(GPIOB,GPIO_Pin_10) // IIC_SCL置低 #define IIC_SDA_H() GPIO_SetBits(GPIOB,GPIO_Pin_11) // IIC_SDA置高 #define IIC_SDA_L() GPIO_ResetBits(GPIOB,GPIO_Pin_11) // IIC_SDA置低

2.ASCII字库与OLED缓存

ASCII共有127个字符,前32个为特殊功能(回车、换行、Tab等)。我们把字库放在一个127x6的数组里,里面的元素是无符号8位二进制数(u8或者unsigned char),数组的每一行正好构成一个ASCII字符(能完整显示所有ASCII字符所需的分辨率最小为8x6,在文章动态扫描显示原理中有详细介绍)。这里我简化了特殊功能,全部显示为空白,或者说为空格。

这里还需要声明一个数组作为OLED内部SRAM的缓存。提高刷新的效果。

unsigned char Dictionary_ASCII8x6[127][6]= { 0,0,0,0,0,0,//0 0,0,0,0,0,0,//1 0,0,0,0,0,0,//2 0,0,0,0,0,0,//3 0,0,0,0,0,0,//4 0,0,0,0,0,0,//5 0,0,0,0,0,0,//6 0,0,0,0,0,0,//7 0,0,0,0,0,0,//8 0,0,0,0,0,0,//9 0,0,0,0,0,0,//10 0,0,0,0,0,0,//11 0,0,0,0,0,0,//12 0,0,0,0,0,0,//13 0,0,0,0,0,0,//14 0,0,0,0,0,0,//15 0,0,0,0,0,0,//16 0,0,0,0,0,0,//17 0,0,0,0,0,0,//18 0,0,0,0,0,0,//19 0,0,0,0,0,0,//20 0,0,0,0,0,0,//21 0,0,0,0,0,0,//22 0,0,0,0,0,0,//23 0,0,0,0,0,0,//24 0,0,0,0,0,0,//25 0,0,0,0,0,0,//26 0,0,0,0,0,0,//27 0,0,0,0,0,0,//28 0,0,0,0,0,0,//29 0,0,0,0,0,0,//30 0,0,0,0,0,0,//31 0-31为特殊功能,如换行、回车 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//32 空格 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,//33 ! 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,//34 " 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,//35 # 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,//36 $ 0x00, 0x23, 0x13, 0x08, 0x64, 0x62,//37 % 0x00, 0x36, 0x49, 0x55, 0x22, 0x50,//38 & 0x00, 0x00, 0x05, 0x03, 0x00, 0x00,//39 ' 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,//40 ( 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,//41 ) 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,//42 * 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,//43 + 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,//44 , 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,//45 - 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,//46 . 0x00, 0x20, 0x10, 0x08, 0x04, 0x02,//47 / 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,//48 0 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,//49 1 0x00, 0x42, 0x61, 0x51, 0x49, 0x46,//50 2 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,//51 3 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,//52 4 0x00, 0x27, 0x45, 0x45, 0x45, 0x39,//53 5 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,//54 6 0x00, 0x01, 0x71, 0x09, 0x05, 0x03,//55 7 0x00, 0x36, 0x49, 0x49, 0x49, 0x36,//56 8 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,//57 9 0x00, 0x00, 0x36, 0x36, 0x00, 0x00,//58 : 0x00, 0x00, 0x56, 0x36, 0x00, 0x00,//59 ; 0x00, 0x08, 0x14, 0x22, 0x41, 0x00,//60 < 0x00, 0x14, 0x14, 0x14, 0x14, 0x14,//61 = 0x00, 0x00, 0x41, 0x22, 0x14, 0x08,//62 > 0x00, 0x02, 0x01, 0x51, 0x09, 0x06,//63 ? 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,//64 @ 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,//65 A 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,//66 B 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,//67 C 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,//68 D 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,//69 E 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,//70 F 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,//71 G 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,//72 H 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,//73 I 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,//74 J 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,//75 K 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,//76 L 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,//77 M 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,//78 N 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,//79 O 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,//80 P 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,//81 Q 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,//82 R 0x00, 0x46, 0x49, 0x49, 0x49, 0x31,//83 S 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,//84 T 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,//85 U 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,//86 V 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,//87 W 0x00, 0x63, 0x14, 0x08, 0x14, 0x63,//88 X 0x00, 0x07, 0x08, 0x70, 0x08, 0x07,//89 Y 0x00, 0x61, 0x51, 0x49, 0x45, 0x43,//90 Z 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,//91 [ 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,/*92 \ */ 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,//93 ] 0x00, 0x04, 0x02, 0x01, 0x02, 0x04,//94 ^ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40,//95 _ 0x00, 0x00, 0x01, 0x02, 0x04, 0x00,//96 ' 0x00, 0x20, 0x54, 0x54, 0x54, 0x78,//97 a 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,//98 b 0x00, 0x38, 0x44, 0x44, 0x44, 0x20,//99 c 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,//100 d 0x00, 0x38, 0x54, 0x54, 0x54, 0x18,//101 e 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,//102 f 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,//103 g 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,//104 h 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,//105 i 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,//106 j 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,//107 k 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,//108 l 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,//109 m 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,//110 n 0x00, 0x38, 0x44, 0x44, 0x44, 0x38,//111 o 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,//112 p 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,//113 q 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,//114 r 0x00, 0x48, 0x54, 0x54, 0x54, 0x20,//115 s 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,//116 t 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,//117 u 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,//118 v 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,//119 w 0x00, 0x44, 0x28, 0x10, 0x28, 0x44,//120 x 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,//121 y 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,//122 z 0x00, 0x08, 0x77, 0x41, 0x00, 0x00,//123 { 0x00, 0x08, 0x7F, 0x00, 0x00, 0x00,//124 | 0x00, 0x41, 0x77, 0x08, 0x00, 0x00,//125 } 0x00, 0x08, 0x04, 0x08, 0x10, 0x08 //126 ~ }; u8 SDRAM[8][128]={0}; //SRAM缓存

3.GPIO初始化

这里我定义一个函数,用来给IIC的软件模拟引脚SCL(PB10)、SDA(PB11)、res复位脚初始化。模式全部为推挽输出。

void IIC_UserInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11; //10--SCL 11--SDA GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //作为屏幕的RSE脚,4线OLED屏幕可省略 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC,&GPIO_InitStructure); }

4.延时函数

为了方便理解,这里就不使用定时器了,直接Delay

void Delay_us(int Time) //us延时函数 { int i=0; while(Time--) { i=8; while(i--); } return; }

5.IIC-SDA输入输出模式切换函数

IIC通讯时,单片机发送数据后需要等待应答,这时模拟SDA要切换到输入模式(上拉输入),收到应答后又要切回输出模式(推挽输出)。具体过程可参靠文章软件模拟IIC通信,里面有详细介绍。

void SDA_OUT(void) //输出模式 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出 GPIO_Init(GPIOB, &GPIO_InitStructure); } void SDA_IN(void) //输入模式 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入模式 GPIO_Init(GPIOB, &GPIO_InitStructure); }

6.IIC软件模拟信号

软件模拟起始信号、停止信号、应答信号、数据发送

void IIC_Start(void) //起始信号 { SDA_OUT(); //SDA切换输出模式 IIC_SDA_H(); //SDA置高 IIC_SCL_H(); //SCL置高 Delay_us(1); IIC_SDA_L(); //SDA置低 Delay_us(1); IIC_SCL_L(); //SCL置低 Delay_us(1); } void IIC_Stop(void) //停止信号 { IIC_SCL_H(); IIC_SDA_L(); Delay_us(1); IIC_SDA_H(); Delay_us(1); } u8 IIC_Wait_Ask(void) //应答信号 { int count=0; IIC_SDA_H(); SDA_IN(); IIC_SCL_H(); Delay_us(1); while(Read_IIC_SDA) { count++; if(count>250) { IIC_Stop(); //无应答则发停止信号,停止通信 return 1; } } IIC_SCL_L(); Delay_us(1); return 0; } void IIC_WriteByte(u8 data) //发送1Byte数据 { u8 i; SDA_OUT(); for(i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有