oled的一套stm32实验2(自己的实验)
stm32与OLED屏接口的引脚介绍:
CS————GPIOD3;
RST————GPIOD4;
DC—————GPIOD5;
D0——————GPIOD6;
D1——————GPIOD7;
上是我参考别人的oled引脚的接线
但是 我买的oled模块和别人的不是很一样,虽然也是spi通信的
看一下我的接线:
模块与stm32:
GND--GND
VCC--3.3v
SCL--PD6 :这个是时钟
SDA--PD7 :这个是传输数据的,也就是数据线spi本应是两条的,但是屏幕并没有返回值,所以只有一条了
RES--PD4 :复位,
DC--PD5 :这个是命令或数据指示位,当为高电平的时候表示数据,低电平的时候表示命令
根据上面的取模方式,就要有相对应的代码才行:
下面这行代码就是对应的这种取模方式,这个是32*32的汉字.
void OLED_ShowChinese(int x, int y, const unsigned char *p)
{
int i = 0;
OLED_Coord(x, y);
for(i = 0; i < 32; i+=2) //因为汉字是占了屏幕里的两行,所以要有上下两个部分. 汉字的宽是32个像素.
{
SPI_Write(p[i], OLED_Data);
}
OLED_Coord(x, y+1);
for(i = 1; i < 32; i+=2)
{
SPI_Write(p[i], OLED_Data);
}
}
////////////////////////////////////////////////////////////////////////////////
下面我们要用stm32自带的spi库去配置oled屏幕
我们先看接线:
SPI1->CS ------ PA4----CS 这个是片选,我的屏幕上没有
SPI1->MISO ------ PA6-----D1 这个是spi
#include "oled.h" #include "stm32f10x.h" const unsigned char xing[]= { 0x10,0x40,0x10,0x22,0xF0,0x15,0x1F,0x08, 0x10,0x16,0xF0,0x21,0x40,0x40,0x3C,0x42, 0x10,0x42,0x10,0x42,0xFF,0x7F,0x10,0x42, 0x10,0x42,0x10,0x42,0x00,0x40,0x00,0x00};/*"姓",0*/ const unsigned char A[]= { 0x00,0x20,0x00,0x3C,0xC0,0x23,0x38,0x02, 0xE0,0x02,0x00,0x27,0x00,0x38,0x00,0x20};/*"A",0*/ const unsigned char ming[]= { 0x00,0x04,0x20,0x04,0x20,0x04,0x10,0x02, 0x08,0xFE,0x14,0x43,0x67,0x43,0x84,0x42, 0x44,0x42,0x24,0x42,0x14,0x42,0x0C,0x42, 0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00};/*"名",0*/ const unsigned char ASCII_Colon[]= { 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30, 0xC0,0x30,0x00,0x00,0x00,0x00,0x00,0x00};/*":",0*/ const unsigned char xue[]= { 0x40,0x04,0x30,0x04,0x11,0x04,0x96,0x04, 0x90,0x04,0x90,0x44,0x91,0x84,0x96,0x7E, 0x90,0x06,0x90,0x05,0x98,0x04,0x14,0x04, 0x13,0x04,0x50,0x04,0x30,0x04,0x00,0x00};/*"学",0*/ const unsigned char hao[]= { 0x80,0x00,0x80,0x00,0x80,0x00,0xBE,0x06, 0xA2,0x05,0xA2,0x04,0xA2,0x04,0xA2,0x04, 0xA2,0x44,0xA2,0x84,0xA2,0x44,0xBE,0x3C, 0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00};/*"号",0*/ const unsigned char liao[] = // 瞭望,不知道为什么不行,这个好像是定义了一个结构体,实际上,我可以让文字的显示更加灵活. { 0x10,0x04,0x10,0x03,0xD0,0x00,0xFF,0xFF, 0x90,0x80,0x10,0x41,0x00,0x20,0xFC,0x1F, 0x04,0x00,0x04,0x00,0x04,0x00,0xFE,0x3F, 0x04,0x40,0x00,0x40,0x00,0x70,0x00,0x00, }; const unsigned char wang[] = { 0x10,0x04,0x10,0x03,0xD0,0x00,0xFF,0xFF, 0x90,0x20,0x18,0x11,0xE8,0x8F,0x08,0x81, 0xE8,0x5F,0x08,0x21,0xFF,0x17,0x08,0x38, 0x0A,0x46,0x8C,0x81,0x08,0xE0,0x00,0x00 }; /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; //开启GPIOD的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //设置GPIO的基本参数 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度50MHz GPIO_Init(GPIOD, &GPIO_InitStruct); GPIO_SetBits(GPIOD, GPIO_Pin_4 | GPIO_Pin_5 ); } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ //下面是spi的协议实现部分 void SPI_Write(char data, int Mode) { if(Mode) { OLED_DC(1); //DC引脚输入高,表示写数据 } else { OLED_DC(0); //DC引脚输入低,表示写命令 } //OLED_CS(0); //CS引脚输入低,片选使能 SPI_I2S_SendData(SPI1, data); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//判断有没有传输完,对于传输是很重要的. OLED_DC(0); //DC引脚输入低, 命令行恢复默认. //OLED_CS(1); //CS引脚输入高,片选失能 } void spi1(void) //spi1的配置. { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; //经常把这个开关忘掉 /* SPI的IO口和SPI外设打开时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//也经常把这个忘掉 /* SPI的IO口设置 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7); //PA5.6.7上拉 /***************************************************************************/ /************************* 设置SPI的参数 ***********************************/ /***************************************************************************/ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//选择全双工SPI模式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8位SPI SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟悬空高电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //在第二个时钟采集数据 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //Nss使用软件控制 /* 选择波特率预分频为256 */ SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//从最高位开始传输 SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Cmd(SPI1, ENABLE); SPI_Init(SPI1, &SPI_InitStructure); } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ //坐标的实现 void OLED_Coord(unsigned char x, unsigned char y) { SPI_Write((0xb0+(y & 0x0f)), OLED_Order); //设置OLED显示的页 SPI_Write((((x & 0xf0)>>4) | 0x10), OLED_Order);//设置OLED水平坐标的高4位 根据上面那张图分析,这是取x的高四位, SPI_Write((x & 0x0f)|0x01, OLED_Order); //设置OLED水平坐标的低4位 至于为什么要|0x01,可能是为了防止太靠边。 } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_Clear(void) { int i = 0, j = 0; for(i = 0; i < 8; i++) { OLED_Coord(0, i); for(j = 0; j < 128; j++) { SPI_Write(0x00, OLED_Data); } } } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_Display_Off(void) { //电荷泵设置(初始化时必须打开,否则看不到显示) SPI_Write(0x8D, OLED_Order); SPI_Write(0x10, OLED_Order);//bit2 0:关闭 1:打开 SPI_Write(0xAE, OLED_Order);//0xAE:关闭显示 } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_Display_On(void) { //电荷泵设置(初始化时必须打开,否则看不到显示) SPI_Write(0x8D, OLED_Order); SPI_Write(0x14, OLED_Order);//bit2 0:关闭 1:打开 SPI_Write(0xAF, OLED_Order);//0xAF:开显示 } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_Init(void) { OLED_GPIO_Init(); OLED_RST(1); delay(6000); //这里有一个延迟,即便是使用滴答定时器也终究是delay,所以怎样去除这个delay呢? OLED_RST(0); delay(6000); //怎样去除这个delay呢??? OLED_RST(1); SPI_Write(0xAE, OLED_Order);//0xAE:关显示 SPI_Write(0x00, OLED_Order);//设置低列地址 SPI_Write(0x10, OLED_Order);//设置高列地址 //设置行显示的开始地址(0-63) //40-47: (01xxxxx) SPI_Write(0x40, OLED_Order); //设置对比度 SPI_Write(0x81, OLED_Order); SPI_Write(0xff, OLED_Order);//这个值越大,屏幕越亮(和上条指令一起使用)(0x00-0xff) SPI_Write(0xA1, OLED_Order);//0xA1: 左右反置, 0xA0: 正常显示(默认0xA0) SPI_Write(0xC8, OLED_Order);//0xC8: 上下反置, 0xC0: 正常显示(默认0xC0) //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮) //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮) SPI_Write(0xA6, OLED_Order); SPI_Write(0xA8, OLED_Order);//设置多路复用率(1-64) SPI_Write(0x3F, OLED_Order);//(0x01-0x3f)(默认为3f) //设置显示抵消移位映射内存计数器 SPI_Write(0xD3, OLED_Order); SPI_Write(0x00, OLED_Order);//(0x00-0x3f)(默认为0x00) //设置显示时钟分频因子/振荡器频率 SPI_Write(0xD5, OLED_Order); //低4位定义显示时钟(屏幕的刷新时间)(默认:0000)分频因子= [3:0]+1 //高4位定义振荡器频率(默认:1000) SPI_Write(0x80, OLED_Order);// //时钟预充电周期 SPI_Write(0xD9, OLED_Order); SPI_Write(0xF1, OLED_Order);//[3:0],PHASE 1; [7:4] PHASE 2 //设置COM硬件应脚配置 SPI_Write(0xDA, OLED_Order); SPI_Write(0x12, OLED_Order);//[5:4] 默认:01 SPI_Write(0xDB, OLED_Order);// SPI_Write(0x40, OLED_Order);// //设置内存寻址方式 SPI_Write(0x20, OLED_Order); //00: 表示水平寻址方式 //01: 表示垂直寻址方式 //10: 表示页寻址方式(默认方式) SPI_Write(0x02, OLED_Order);// //电荷泵设置(初始化时必须打开,否则看不到显示) SPI_Write(0x8D, OLED_Order); SPI_Write(0x14, OLED_Order);//bit2 0:关闭 1:打开 //设置是否全部显示 0xA4: 禁止全部显示 SPI_Write(0xA4, OLED_Order); //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮) //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮) SPI_Write(0xA6, OLED_Order);// SPI_Write(0xAF, OLED_Order);//0xAF:开显示 SPI_Write(0xAF, OLED_Order);//0xAF:开显示 OLED_Clear(); } /******************************************************************************* * 函 数 名 : * 函数功能 : * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_ShowChinese(int x, int y, const unsigned char *p) { int i = 0; OLED_Coord(x, y); for(i = 0; i < 32; i+=2) //因为汉字是占了屏幕里的两行,所以要有上下两个部分. 汉字的宽是32个像素. { SPI_Write(p[i], OLED_Data); } OLED_Coord(x, y+1); for(i = 1; i < 32; i+=2) { SPI_Write(p[i], OLED_Data); } } /******************************************************************************* * 函 数 名 : OLED_ShowChar * 函数功能 : 输出一个ascii * 输 入 : * 输 出 : 无 *******************************************************************************/ void OLED_ShowChar(int x, int y, const unsigned char *p) { int i = 0; OLED_Coord(x, y); for(i = 0; i < 16; i+=2) { SPI_Write(p[i], OLED_Data); } OLED_Coord(x, y+1); for(i = 1; i < 16; i+=2) { SPI_Write(p[i], OLED_Data); } }
oled.h文件:
#ifndef _oled_H #define _oled_H #include "stm32f10x.h" extern const unsigned char xing[]; extern const unsigned char A[]; extern const unsigned char ming[]; extern const unsigned char ASCII_Colon[]; extern const unsigned char xue[]; extern const unsigned char hao[]; extern const unsigned char liao[]; extern const unsigned char wang[]; //也不知上面这些define是否应该定义在.h文件,是不是定义在.c文件中更合理,感觉不是,因为定义在.h中主函数可以调用头文件来应用.[]??? #define OLED_CS(X) X?GPIO_SetBits(GPIOD, GPIO_Pin_3):GPIO_ResetBits(GPIOD, GPIO_Pin_3) //X为1时对应GPIO端口输出高电平,X为0时对应GPIO端口输出低电平 #define OLED_RST(X) X?GPIO_SetBits(GPIOD, GPIO_Pin_4):GPIO_ResetBits(GPIOD, GPIO_Pin_4) #define OLED_DC(X) X?GPIO_SetBits(GPIOD, GPIO_Pin_5):GPIO_ResetBits(GPIOD, GPIO_Pin_5) #define OLED_D0(X) X?GPIO_SetBits(GPIOD, GPIO_Pin_6):GPIO_ResetBits(GPIOD, GPIO_Pin_6) #define OLED_D1(X) X?GPIO_SetBits(GPIOD, GPIO_Pin_7):GPIO_ResetBits(GPIOD, GPIO_Pin_7) #define OLED_Order 0//定义写命令 我以前粘贴的时候,这里虽然没有出错,但是在相应的.c文件中出现了错误.就是因为这里粘贴了不该粘贴的东西. #define OLED_Data 1//定义写数据 void OLED_GPIO_Init(void); void delay(u32 i); void SPI_Write(char data, int Mode); void OLED_Coord(unsigned char x, unsigned char y); void OLED_Clear(void); void OLED_Display_Off(void); void OLED_Display_On(void); void OLED_Init(void); void OLED_ShowChinese(int x, int y, const unsigned char *p); void OLED_ShowChar(int x, int y, const unsigned char *p); void spi1(void); #endif
下面是主函数:
/******************************************************************************* * * 普中科技 -------------------------------------------------------------------------------- * 实 验 名 : 蜂鸣器实验 * 实验说明 : 通过IO产生一定频率的脉冲实现蜂鸣器发声 * 连接方式 : * 注 意 : 所用函数在beep.c文件内 *******************************************************************************/ //#include "stm32f10x.h" #include "public.h" //公共函数头文件 #include "oled.h" //#include "beep.h" //蜂鸣器函数头文件 /**************************************************************************** * Function Name : main * Description : Main program. * Input : None * Output : None * Return : None ****************************************************************************/ int main() { //SysClockInit(); SystemInit(); //这里还是有点问题的,我该怎样甚至时钟的函数. //OLED_GPIO_Init(); spi1(); OLED_Init(); //程序就是一层一层的,协议也是一层一层的.应该学会去拨开. OLED_ShowChinese(0, 0, xing);//‘姓’ //这个xing[]的数组是定义在.c文件中的,用extern在.h文件中拓展,之后主函数里include相应的.h就可以在main函数里进行调用这个变量了. OLED_ShowChinese(18, 0, ming);//‘名’ //OLED_ShowChar(36, 0, ASCII_Colon);//‘:’ OLED_ShowChinese(0, 2, xue);//‘学’ OLED_ShowChinese(18, 2, hao);//‘号’ //OLED_ShowChar(36, 2, ASCII_Colon);//‘:’ OLED_ShowChinese(0, 4, liao);//‘瞭’ OLED_ShowChinese(18, 4, wang);//‘望’ //OLED_ShowChar(36, 4, ASCII_Colon);//‘:’ while(1) { } }