STM32
直播中

ningkui

12年用户 831经验值
擅长:电源/新能源
私信 关注
[问答]

怎样通过SPI总线去实现OLED屏幕显示呢

怎样通过SPI总线去实现OLED屏幕显示呢?
如何去完成STM32 SPI协议接口下的OLED屏显示实验?

回帖(1)

曾艳

2021-11-17 15:18:50
  任务要求
  练习通过SPI总线实现OLED屏幕显示。显示自己的学号和姓名。
  显示AHT20的温度和湿度;
  上下或左右的滑动显示长字符;
  本人所用开发板:野火STM32F103指南者;
  代码编写烧录:KEIL5
  所用协议:SPI;
  SPI协议接口
  SPI协议(SerialPeripheralInterface),即串行外围设备接口,是一种高速全双工的通信总线。
  基本通信过程:
  
  SPI接口位置:
  SPI引脚:
  MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据;
  MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据;
  SCK:串口时钟,作为主设备的输入,从设备的输入;
  NSS:从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用来作为“片选引脚”,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。
  SPI下的STM32与OLED连接
  显示文本
  1.在OLED官网下载例程:
  
  下载完成解压后再用KEIL打开SPI对应的OLED显示例程“0.96inch_OLED_Demo_STM32F103ZET6_Hardware_4-wire_SPI”,如下:
  
  2.STM32与OLED的连接依据main.c程序里的注释提示进行连接即可,如下:
  
  注意:此时的OLED的CS接口不用连接,只需要六根线进行STM32与OLED的连接。
  完成后,模块显示如下:
  此时直接编译烧录例程,不用改动,显示如下:
  此时如果OLED屏不显示,可能是接线有问题,检查即可。
  3.改写程序:
  在oledfont.h头文件里添加个人需要显示的汉字字模,此时需要利用PCtoLCD软件,打开界面如下:
  
  该软件为野火资料包里的开发软件自带。
  关于字模软件的使用详见野火自带教程。
  此时选取字模,添加进数组。如下:
  const typFNT_GB16 cfont16[] =
  {
  “马”,0x00,0x00,0x7F,0xE0,0x00,0x20,0x00,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x1F,0xFC,
  0x00,0x04,0x00,0x04,0x00,0x04,0xFF,0xE4,0x00,0x04,0x00,0x04,0x00,0x28,0x00,0x10,/*“妈”,0*/
  “舒”,0x10,0x00,0x11,0xF8,0x28,0x08,0x44,0x50,0x82,0x20,0x7C,0x10,0x13,0xFE,0x10,0x22,
  0xFE,0x24,0x10,0x20,0x10,0x20,0x7C,0x20,0x44,0x20,0x44,0x20,0x7C,0xA0,0x44,0x40,/*“舒”,0*/
  “娅”,0x20,0x00,0x23,0xFC,0x20,0x90,0x20,0x90,0xF8,0x90,0x48,0x92,0x4C,0x92,0x4A,0x94,
  0x8A,0x94,0x4A,0x98,0x30,0x90,0x10,0x90,0x28,0x90,0x48,0x90,0x87,0xFE,0x00,0x00,/*“娅”,0*/
  注意:此时我选择的是1616的OLED汉字显示,因此在添加字模时,也是添加进1616汉字显示对应的数组。添加后注意保存。
  再进入test.c进行修改,将void TEST_MainPage(void)函数修改。如下:
  void TEST_MainPage(void)
  {
  GUI_ShowString(20,0,“631807030324”,8,1);
  GUI_ShowCHinese(16,20,16,“马舒娅”,1);
  delay_ms(1500);
  }
  修改完成,再进入main.c文件进行修改,如下:
  #include “delay.h”
  #include “sys.h”
  #include “oled.h”
  #include “gui.h”
  #include “test.h”
  int main(void)
  {
  delay_init(); //延时函数初始化
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIc中断分组2:2位抢占优先级,2位响应优先级
  OLED_Init(); //初始化OLED
  OLED_Clear(0); //清屏,全黑
  while(1)
  {
  TEST_MainPage(); //主页面显示姓名与学号
  OLED_Clear(0);
  }
  }
  此时全部程序已修改完毕,现在进行编译烧录,即可成功运行。
  显示温湿度与文本的滚动显示
  前提是利用I2C已经做出了基于STM32与AHT20的温湿度检测。
  温湿度显示
  1,在上文中的例程里加入之前测量温湿度的文件与头文件;
  如下:
  
  2,需要在主程序main()中加入读取温湿度的函数,如下:
  void read_AHT20_once(void)
  {
  delay_ms(10);
  reset_AHT20();
  delay_ms(10);
  init_AHT20();
  delay_ms(10);
  startMeasure_AHT20();
  delay_ms(80);
  read_AHT20();
  delay_ms(5);
  }
  3,读取在OLED显示温湿度,如下:
  void reset_AHT20(void)
  {
  //Êý¾Ý´«Ê俪ʼÐźÅ
  I2C_Start();
  //·¢ËÍÊý¾Ý
  I2C_WriteByte(0x70);
  //½ÓÊÕ ACK ÐźÅ
  ack_status = Receive_ACK();
  //·¢ËÍÈí¸´Î»ÃüÁÖØÆô´«¸ÐÆ÷ϵͳ£©
  I2C_WriteByte(0xBA);
  //½ÓÊÕ ACK ÐźÅ
  ack_status = Receive_ACK();
  //Í£Ö¹ I2C ЭÒé
  I2C_Stop();
  }
  //0x70 ¡ª》 0111 0000 Ç°Æßλ±íʾ I2C µØÖ·£¬µÚ°ËλΪ0£¬±íʾ write
  //0xE1 ¡ª》 ¿´×´Ì¬×ÖµÄУ׼ʹÄÜλBit[3]ÊÇ·ñΪ 1
  //0x08 0x00 ¡ª》 0xBE ÃüÁîµÄÁ½¸ö²ÎÊý£¬Ïê¼û AHT20 ²Î¿¼ÊÖ²á
  void init_AHT20(void)
  {
  //´«Ê俪ʼ
  I2C_Start();
  //дÈë 0x70 Êý¾Ý
  I2C_WriteByte(0x70);
  //½ÓÊÕ ACK ÐźÅ
  ack_status = Receive_ACK();
  //дÈë 0xE1 Êý¾Ý
  I2C_WriteByte(0xE1);
  ack_status = Receive_ACK();
  //дÈë 0x08 Êý¾Ý
  I2C_WriteByte(0x08);
  ack_status = Receive_ACK();
  //дÈë 0x00 Êý¾Ý
  I2C_WriteByte(0x00);
  ack_status = Receive_ACK();
  //Í£Ö¹ I2C ЭÒé
  I2C_Stop();
  }
  //0x70 ¡ª》 0111 0000 Ç°Æßλ±íʾ I2C µØÖ·£¬µÚ°ËλΪ0£¬±íʾ write
  //0xAC ¡ª》 ´¥·¢²âÁ¿
  //0x33 0x00 ¡ª》 0xAC ÃüÁîµÄÁ½¸ö²ÎÊý£¬Ïê¼û AHT20 ²Î¿¼ÊÖ²á
  void startMeasure_AHT20(void)
  {
  //Æô¶¯ I2C ЭÒé
  I2C_Start();
  I2C_WriteByte(0x70);
  ack_status = Receive_ACK();
  I2C_WriteByte(0xAC);
  ack_status = Receive_ACK();
  I2C_WriteByte(0x33);
  ack_status = Receive_ACK();
  I2C_WriteByte(0x00);
  ack_status = Receive_ACK();
  I2C_Stop();
  }
  void read_AHT20(void)
  {
  uint8_t i;
  //³õʼ»¯ readByte Êý×é
  for(i=0; i《6; i++)
  {
  readByte[i]=0;
  }
  I2C_Start();
  //ͨ¹ý·¢ËÍ 0x71 ¿ÉÒÔ»ñÈ¡Ò»¸ö×Ö½ÚµÄ״̬×Ö
  I2C_WriteByte(0x71);
  ack_status = Receive_ACK();
  //½ÓÊÕ 6 ¸ö 8 bitµÄÊý¾Ý
  readByte[0]= I2C_ReadByte();
  //·¢ËÍ ACK ÐźÅ
  Send_ACK();
  readByte[1]= I2C_ReadByte();
  Send_ACK();
  readByte[2]= I2C_ReadByte();
  Send_ACK();
  readByte[3]= I2C_ReadByte();
  Send_ACK();
  readByte[4]= I2C_ReadByte();
  Send_ACK();
  readByte[5]= I2C_ReadByte();
  //·¢ËÍ NACK ÐźÅ
  SendNot_Ack();
  I2C_Stop();
  //ÎÂʪ¶ÈµÄ¶þ½øÖÆÊý¾Ý´¦Àí
  //0x68 = 0110 1000
  //0x08 = 0000 1000
  if( (readByte[0] & 0x68) == 0x08 )
  {
  H1 = readByte[1];
  //H1 ×óÒÆ 8 λ²¢Óë readByte[2] Ïà»ò
  H1 = (H1《《8) | readByte[2];
  H1 = (H1《《8) | readByte[3];
  //H1 ÓÒÒÆ 4 λ
  H1 = H1》》4;
  H1 = (H1*1000)/1024/1024;
  T1 = readByte[3];
  //ÓëÔËËã
  T1 = T1 & 0x0000000F;
  T1 = (T1《《8) | readByte[4];
  T1 = (T1《《8) | readByte[5];
  T1 = (T1*2000)/1024/1024 - 500;
  AHT20_OutData[0] = (H1》》8) & 0x000000FF;
  AHT20_OutData[1] = H1 & 0x000000FF;
  AHT20_OutData[2] = (T1》》8) & 0x000000FF;
  AHT20_OutData[3] = T1 & 0x000000FF;
  }
  else
  {
  AHT20_OutData[0] = 0xFF;
  AHT20_OutData[1] = 0xFF;
  AHT20_OutData[2] = 0xFF;
  AHT20_OutData[3] = 0xFF;
  }
  /*
  printf(“Íê³É£¡n”);
  printf(“----ζÈ:%d%d.%d ¡ãCn”,T1/100,(T1/10)%10,T1%10);
  printf(“----ʪ¶È:%d%d.%d %%”,H1/100,(H1/10)%10,H1%10);
  printf(“nn”);
  */
  Show_OLED();
  }
  //ת»¯×Ö·û´®Êä³öµ½ OLED ÉÏ
  void Show_OLED(void)
  {
  t = T1/100;
  switch(t)
  {
  case 0:break;
  case 1:strTemp1 = “1”;break;
  case 2:strTemp1 = “2”;break;
  case 3:strTemp1 = “3”;break;
  case 4:strTemp1 = “4”;break;
  case 5:strTemp1 = “5”;break;
  case 6:strTemp1 = “6”;break;
  case 7:strTemp1 = “7”;break;
  case 8:strTemp1 = “8”;break;
  case 9:strTemp1 = “9”;break;
  }
  t = (T1/10)%10;
  switch(t)
  {
  case 0:strTemp2 = “0”;break;
  case 1:strTemp2 = “1”;break;
  case 2:strTemp2 = “2”;break;
  case 3:strTemp2 = “3”;break;
  case 4:strTemp2 = “4”;break;
  case 5:strTemp2 = “5”;break;
  case 6:strTemp2 = “6”;break;
  case 7:strTemp2 = “7”;break;
  case 8:strTemp2 = “8”;break;
  case 9:strTemp2 = “9”;break;
  }
  t = T1%10;
  switch(t)
  {
  case 0:strTemp3 = “0”;break;
  case 1:strTemp3 = “1”;break;
  case 2:strTemp3 = “2”;break;
  case 3:strTemp3 = “3”;break;
  case 4:strTemp3 = “4”;break;
  case 5:strTemp3 = “5”;break;
  case 6:strTemp3 = “6”;break;
  case 7:strTemp3 = “7”;break;
  case 8:strTemp3 = “8”;break;
  case 9:strTemp3 = “9”;break;
  }
  t = H1/100;
  switch(t)
  {
  case 0:break;
  case 1:strHumi1 = “1”;break;
  case 2:strHumi1 = “2”;break;
  case 3:strHumi1 = “3”;break;
  case 4:strHumi1 = “4”;break;
  case 5:strHumi1 = “5”;break;
  case 6:strHumi1 = “6”;break;
  case 7:strHumi1 = “7”;break;
  case 8:strHumi1 = “8”;break;
  case 9:strHumi1 = “9”;break;
  }
  t = H1/100;
  switch(t)
  {
  case 0:strHumi2 = “0”;break;
  case 1:strHumi2 = “1”;break;
  case 2:strHumi2 = “2”;break;
  case 3:strHumi2 = “3”;break;
  case 4:strHumi2 = “4”;break;
  case 5:strHumi2 = “5”;break;
  case 6:strHumi2 = “6”;break;
  case 7:strHumi2 = “7”;break;
  case 8:strHumi2 = “8”;break;
  case 9:strHumi2 = “9”;break;
  }
  t = H1/100;
  switch(t)
  {
  case 0:strHumi3 = “0”;break;
  case 1:strHumi3 = “1”;break;
  case 2:strHumi3 = “2”;break;
  case 3:strHumi3 = “3”;break;
  case 4:strHumi3 = “4”;break;
  case 5:strHumi3 = “5”;break;
  case 6:strHumi3 = “6”;break;
  case 7:strHumi3 = “7”;break;
  case 8:strHumi3 = “8”;break;
  case 9:strHumi3 = “9”;break;
  }
  GUI_ShowString(40,32,“ ”,16,1);
  GUI_ShowString(40,48,“ ”,16,1);
  GUI_ShowCHinese(0,32,16,“ζȣº”,1);
  GUI_ShowString(40,32,strTemp1,16,1);
  GUI_ShowString(48,32,strTemp2,16,1);
  GUI_ShowString(56,32,“。”,16,1);
  GUI_ShowString(64,32,strTemp3,16,1);
  GUI_ShowCHinese(72,32,16,“¡æ”,1);
  GUI_ShowCHinese(0,48,16,“ʪ¶È£º”,1);
  GUI_ShowString(40,48,strHumi1,16,1);
  GUI_ShowString(48,48,strHumi2,16,1);
  GUI_ShowString(56,48,“。”,16,1);
  GUI_ShowString(64,48,strHumi3,16,1);
  GUI_ShowCHinese(72,48,16,“£¥”,1);
  }
  文本滚动显示
  1,在上文中的例程里加入水平滚动的·函数,如下:
  OLED_WR_Byte(0x2E,OLED_CMD);
  OLED_WR_Byte(0x27,OLED_CMD);
  OLED_WR_Byte(0x00,OLED_CMD);
  OLED_WR_Byte(0x00,OLED_CMD);
  OLED_WR_Byte(0x07,OLED_CMD);
  OLED_WR_Byte(0x01,OLED_CMD);
  OLED_WR_Byte(0x00,OLED_CMD);
  OLED_WR_Byte(0xFF,OLED_CMD);
  TEST_xianshi();
  OLED_WR_Byte(0x2F,OLED_CMD);
  2,滚动显示“欢迎来到冬天”,将字模加入到数组,如下:
  “欢”,0x00,0x80,0x00,0x80,0xFC,0x80,0x04,0xFC,0x05,0x04,0x49,0x08,0x2A,0x40,0x14,0x40,
  0x10,0x40,0x28,0xA0,0x24,0xA0,0x45,0x10,0x81,0x10,0x02,0x08,0x04,0x04,0x08,0x02,
  “迎­”,0x00,0x00,0x20,0x80,0x13,0x3C,0x12,0x24,0x02,0x24,0x02,0x24,0xF2,0x24,0x12,0x24,
  0x12,0x24,0x12,0xB4,0x13,0x28,0x12,0x20,0x10,0x20,0x28,0x20,0x47,0xFE,0x00,0x00,
  “来´”,0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x01,0x00,0x11,0x10,0x09,0x10,0x09,0x20,
  0xFF,0xFE,0x03,0x80,0x05,0x40,0x09,0x20,0x31,0x18,0xC1,0x06,0x01,0x00,0x01,0x00,
  “到”,0x00,0x04,0xFF,0x84,0x08,0x04,0x10,0x24,0x22,0x24,0x41,0x24,0xFF,0xA4,0x08,0xA4,
  0x08,0x24,0x08,0x24,0x7F,0x24,0x08,0x24,0x08,0x04,0x0F,0x84,0xF8,0x14,0x40,0x08,
  “冬”,0x04,0x00,0x04,0x00,0x0F,0xF0,0x10,0x10,0x28,0x20,0x44,0x40,0x03,0x80,0x0C,0x60,
  0x30,0x18,0xC0,0x06,0x07,0x00,0x00,0xC0,0x00,0x20,0x0E,0x00,0x01,0x80,0x00,0x40,
  “天”,0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0xFE,0x01,0x00,
  0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0xC0,0x06,
  总结
  本次STM32 SPI协议接口下的OLED屏显示主要任务已完成,对于STM32的SPI接口协议的学习还需更加深入。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分