硬汉嵌入式论坛

 找回密码
 立即注册
查看: 6275|回复: 6
收起左侧

[有问必答] OLED(SH1106)并不从地址0开始显示。

[复制链接]

33

主题

203

回帖

302

积分

高级会员

积分
302
发表于 2018-10-27 16:35:59 | 显示全部楼层 |阅读模式
本帖最后由 diiiiiii 于 2018-10-27 17:09 编辑

初始化SH1106
        gm_write_oled_command(0xAE);

        gm_write_oled_command(0x00);
        gm_write_oled_command(0x10);


        gm_write_oled_command(0x40);//设置起始地址为0
        gm_write_oled_command(0x81);   

        gm_write_oled_command(0xcf);
        gm_write_oled_command(0xa1);

        gm_write_oled_command(0xc8);   

        gm_write_oled_command(0xa6);
        gm_write_oled_command(0xa8);   

        gm_write_oled_command(0x3f);   

        gm_write_oled_command(0xd3);   

        gm_write_oled_command(0x00);

        gm_write_oled_command(0xd5);   

        gm_write_oled_command(0x80);
        gm_write_oled_command(0xd9);   

        gm_write_oled_command(0xf1);
        gm_write_oled_command(0xda);   

        gm_write_oled_command(0x12);
        gm_write_oled_command(0xdb);   

        gm_write_oled_command(0x40);   

        gm_write_oled_command(0x20);   


        gm_write_oled_command(0x02);

        gm_write_oled_command(0x8d);   
        gm_write_oled_command(0x14);   
        gm_write_oled_command(0xa4);   
        gm_write_oled_command(0xa6);   
        gm_write_oled_command(0xaf);   


void gm_set_oled_write_addr(uint8_t x, uint8_t y)//设置显示地址
{
    gm_write_oled_command(0xb0 + y);  

    gm_write_oled_command(((x & 0xf0) >> 4) | 0x10);
    gm_write_oled_command(x & 0x0f);
}

const uint8_t m_pic_matix[] =
{
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,

};

void gm_display_pic(void)//测试函数
{
    uint8_t *p, i, j;

    p = (uint8_t *)m_pic_matix;

    for(j = 0; j < 2; j++)
    {
        gm_set_oled_write_addr(0, j);

        for(i = 0; i < 8; i++)
        {
            gm_write_oled_data(*p);
            p++;         
        }        
    }
}

显示发现,图像的前两列并未显示,即八列的0xff只显示六列

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
发表于 2018-10-28 02:48:12 | 显示全部楼层
没发现你的这个有什么问题,下面是我们的,SPI和FSMC均可用,用的优景。


  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : OLED显示器驱动模块
  5. *        文件名称 : bsp_oled.c
  6. *        版    本 : V1.0
  7. *        说    明 : OLED 屏(128x64)底层驱动程序,驱动芯片型号为 SSD1306.  本驱动程序适合于STM32-V5开发板.
  8. *                                OLED模块挂在FSMC总线上。
  9. *        修改记录 :
  10. *                版本号  日期        作者    说明
  11. *                V1.0    2013-02-01 armfly  正式发布
  12. *
  13. *        Copyright (C), 2010-2012, 安富莱电子 www.armfly.com
  14. *
  15. *********************************************************************************************************
  16. */

  17. #include "bsp.h"
  18. #include "fonts.h"

  19. /*
  20.         安富莱STM32-V4开发板的OLED显示接口为FSMC总线模式。
  21. */

  22. /* 下面2个宏任选 1个; 表示显示方向 */
  23. #define DIR_NORMAL                        /* 此行表示正常显示方向 */
  24. //#define DIR_180                                /* 此行表示翻转180度 */

  25. #ifdef OLED_SPI3_EN
  26.         /*
  27.                 SPI 模式接线定义 (只需要6根杜邦线连接)  本例子采用软件模拟SPI时序

  28.            【OLED模块排针】 【开发板TFT接口(STM32口线)】
  29.                 VCC ----------- 3.3V
  30.                 GND ----------- GND
  31.                  CS ----------- TP_NCS   (PI10)
  32.                 RST ----------- NRESET (也可以不连接)
  33.              D0/SCK ----------- TP_SCK   (PB3)
  34.             D1/SDIN ----------- TP_MOSI  (PB5)
  35.         */
  36.         #define RCC_OLED_PORT (RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOI)                /* GPIO端口时钟 */

  37.         #define OLED_CS_PORT        GPIOI
  38.         #define OLED_CS_PIN                GPIO_Pin_10

  39.         #define OLED_SCK_PORT        GPIOB
  40.         #define OLED_SCK_PIN        GPIO_Pin_3

  41.         #define OLED_SDIN_PORT        GPIOB
  42.         #define OLED_SDIN_PIN        GPIO_Pin_5


  43.         /* 定义IO = 1和 0的代码 (不用更改) */
  44.         #define SSD_CS_1()                OLED_CS_PORT->BSRRL = OLED_CS_PIN
  45.         #define SSD_CS_0()                OLED_CS_PORT->BSRRH = OLED_CS_PIN

  46.         #define SSD_SCK_1()                OLED_SCK_PORT->BSRRL = OLED_SCK_PIN
  47.         #define SSD_SCK_0()                OLED_SCK_PORT->BSRRH = OLED_SCK_PIN

  48.         #define SSD_SDIN_1()        OLED_SDIN_PORT->BSRRL = OLED_SDIN_PIN
  49.         #define SSD_SDIN_0()        OLED_SDIN_PORT->BSRRH = OLED_SDIN_PIN

  50. #else

  51.         /* 定义LCD驱动器的访问地址
  52.                 TFT接口中的RS引脚连接FSMC_A0引脚,由于是16bit模式,RS对应A1地址线,因此
  53.                 OLED_RAM的地址是+2
  54.         */
  55.         #define OLED_BASE       ((uint32_t)(0x6C200000))
  56.         #define OLED_CMD                *(__IO uint16_t *)(OLED_BASE)
  57.         #define OLED_DATA                *(__IO uint16_t *)(OLED_BASE + (1 << 1))                /* FSMC_A0接D/C */

  58.         /*
  59.         1.安富莱OLED模块 80XX 模式接线定义 (需要15根杜邦线连接)
  60.            【OLED模块排针】 【开发板TFT接口(STM32口线)】
  61.                     VCC ----------- 3.3V
  62.                     GND ----------- GND
  63.                      CS ----------- NCS
  64.                 RST ----------- NRESET (也可以不连接)
  65.                     D/C ----------- RS   (FSMC_A18)
  66.                      WE ----------- NWE  (FSMC_NWE)
  67.                      OE ----------- NOE  (FSMC_NOE)
  68.              D0/SCK ----------- DB0  (FSMC_D0)
  69.                 D1/SDIN ----------- DB1  (FSMC_D1)
  70.                      D2 ----------- DB2  (FSMC_D2)
  71.                      D3 ----------- DB3  (FSMC_D3)
  72.                      D4 ----------- DB4  (FSMC_D4)
  73.                      D5 ----------- DB5  (FSMC_D5)
  74.                      D6 ----------- DB6  (FSMC_D6)
  75.                      D7 ----------- DB7  (FSMC_D7)
  76.         */


  77. #endif

  78. /* 12864 OLED的显存镜像,占用1K字节. 共8行,每行128像素 */
  79. static uint8_t s_ucGRAM[8][128];

  80. /* 为了避免刷屏拉幕感太强,引入刷屏标志。
  81. 0 表示显示函数只改写缓冲区,不写屏。1 表示直接写屏(同时写缓冲区) */
  82. static uint8_t s_ucUpdateEn = 1;

  83. static void OLED_ConfigGPIO(void);
  84. static void OLED_WriteCmd(uint8_t _ucCmd);
  85. static void OLED_WriteData(uint8_t _ucData);
  86. static void OLED_BufToPanel(void);

  87. /*
  88. *********************************************************************************************************
  89. *        函 数 名: OLED_InitHard
  90. *        功能说明: 初始化OLED屏
  91. *        形    参:  无
  92. *        返 回 值: 无
  93. *********************************************************************************************************
  94. */
  95. void OLED_InitHard(void)
  96. {
  97.         OLED_ConfigGPIO();

  98.         /* 上电延迟 */
  99.         bsp_DelayMS(50);

  100.          /* 模块厂家提供初始化代码 */
  101.         OLED_WriteCmd(0xAE);        /* 关闭OLED面板显示(休眠) */
  102.         OLED_WriteCmd(0x00);        /* 设置列地址低4bit */
  103.         OLED_WriteCmd(0x10);        /* 设置列地址高4bit */
  104.         OLED_WriteCmd(0x40);        /* 设置起始行地址(低5bit 0-63), 硬件相关*/

  105.         OLED_WriteCmd(0x81);        /* 设置对比度命令(双字节命令),第1个字节是命令,第2个字节是对比度参数0-255 */
  106.         OLED_WriteCmd(0xCF);        /* 设置对比度参数,缺省CF */

  107. #ifdef DIR_NORMAL
  108.         OLED_WriteCmd(0xA0);        /* A0 :列地址0映射到SEG0; A1 :列地址127映射到SEG0 */
  109.         OLED_WriteCmd(0xC0);        /* C0 :正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
  110. #endif

  111. #ifdef DIR_180
  112.         OLED_WriteCmd(0xA1);        /* A0 :列地址0映射到SEG0; A1 :列地址127映射到SEG0 */
  113.         OLED_WriteCmd(0xC8);        /* C0 :正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
  114. #endif

  115.         OLED_WriteCmd(0xA6);        /* A6 : 设置正常显示模式; A7 : 设置为反显模式 */

  116.         OLED_WriteCmd(0xA8);        /* 设置COM路数 */
  117.         OLED_WriteCmd(0x3F);        /* 1 ->(63+1)路 */

  118.         OLED_WriteCmd(0xD3);        /* 设置显示偏移(双字节命令)*/
  119.         OLED_WriteCmd(0x00);        /* 无偏移 */

  120.         OLED_WriteCmd(0xD5);        /* 设置显示时钟分频系数/振荡频率 */
  121.         OLED_WriteCmd(0x80);        /* 设置分频系数,高4bit是分频系数,低4bit是振荡频率 */

  122.         OLED_WriteCmd(0xD9);        /* 设置预充电周期 */
  123.         OLED_WriteCmd(0xF1);        /* [3:0],PHASE 1; [7:4],PHASE 2; */

  124.         OLED_WriteCmd(0xDA);        /* 设置COM脚硬件接线方式 */
  125.         OLED_WriteCmd(0x12);

  126.         OLED_WriteCmd(0xDB);        /* 设置 vcomh 电压倍率 */
  127.         OLED_WriteCmd(0x40);        /* [6:4] 000 = 0.65 x VCC; 0.77 x VCC (RESET); 0.83 x VCC  */

  128.         OLED_WriteCmd(0x8D);        /* 设置充电泵(和下个命令结合使用) */
  129.         OLED_WriteCmd(0x14);        /* 0x14 使能充电泵, 0x10 是关闭 */
  130.         OLED_WriteCmd(0xAF);        /* 打开OLED面板 */
  131. }

  132. /*
  133. *********************************************************************************************************
  134. *        函 数 名: OLED_DispOn
  135. *        功能说明: 打开显示
  136. *        形    参:  无
  137. *        返 回 值: 无
  138. *********************************************************************************************************
  139. */
  140. void OLED_DispOn(void)
  141. {
  142.         OLED_WriteCmd(0x8D);        /* 设置充电泵(和下个命令结合使用) */
  143.         OLED_WriteCmd(0x14);        /* 0x14 使能充电泵, 0x10 是关闭 */
  144.         OLED_WriteCmd(0xAF);        /* 打开OLED面板 */
  145. }

  146. /*
  147. *********************************************************************************************************
  148. *        函 数 名: OLED_DispOff
  149. *        功能说明: 关闭显示
  150. *        形    参:  无
  151. *        返 回 值: 无
  152. *********************************************************************************************************
  153. */
  154. void OLED_DispOff(void)
  155. {
  156.         OLED_WriteCmd(0x8D);        /* 设置充电泵(和下个命令结合使用)*/
  157.         OLED_WriteCmd(0x10);        /* 0x14 使能充电泵,0x10 是关闭 */
  158.         OLED_WriteCmd(0xAE);        /* 打开OLED面板 */
  159. }

  160. /*
  161. *********************************************************************************************************
  162. *        函 数 名: OLED_SetDir
  163. *        功能说明: 设置显示方向
  164. *        形    参: _ucDir = 0 表示正常方向,1表示翻转180度
  165. *        返 回 值: 无
  166. *********************************************************************************************************
  167. */
  168. void OLED_SetDir(uint8_t _ucDir)
  169. {
  170.         if (_ucDir == 0)
  171.         {
  172.                OLED_WriteCmd(0xA0);        /* A0 :列地址0映射到SEG0; A1 :列地址127映射到SEG0 */
  173.                 OLED_WriteCmd(0xC0);        /* C0 :正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
  174.         }
  175.         else
  176.         {
  177.                 OLED_WriteCmd(0xA1);        /* A0 :列地址0映射到SEG0; A1 :列地址127映射到SEG0 */
  178.                 OLED_WriteCmd(0xC8);        /* C0 :正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
  179.         }
  180. }

  181. /*
  182. *********************************************************************************************************
  183. *        函 数 名: OLED_SetContrast
  184. *        功能说明: 设置对比度
  185. *        形    参:  无
  186. *        返 回 值: 无
  187. *********************************************************************************************************
  188. */
  189. void OLED_SetContrast(uint8_t ucValue)
  190. {
  191.         OLED_WriteCmd(0x81);        /* 设置对比度命令(双字节命令),第1个字节是命令,第2个字节是对比度参数0-255 */
  192.         OLED_WriteCmd(ucValue);        /* 设置对比度参数,缺省CF */
  193. }

  194. /*
  195. *********************************************************************************************************
  196. *        函 数 名: OLED_StartDraw
  197. *        功能说明: 开始绘图。以后绘图函数只改写缓冲区,不改写面板显存
  198. *        形    参:  无
  199. *        返 回 值: 无
  200. *********************************************************************************************************
  201. */
  202. void OLED_StartDraw(void)
  203. {
  204.         s_ucUpdateEn = 0;
  205. }

  206. /*
  207. *********************************************************************************************************
  208. *        函 数 名: OLED_EndDraw
  209. *        功能说明: 结束绘图。缓冲区的数据刷新到面板显存。 OLED_StartDraw() 和 OLED_EndDraw() 必须成对使用
  210. *        形    参:  无
  211. *        返 回 值: 无
  212. *********************************************************************************************************
  213. */
  214. void OLED_EndDraw(void)
  215. {
  216.         s_ucUpdateEn = 1;
  217.         OLED_BufToPanel();
  218. }

  219. /*
  220. *********************************************************************************************************
  221. *        函 数 名: OLED_ClrScr
  222. *        功能说明: 清屏
  223. *        形    参:  _ucMode : 0 表示全黑; 0xFF表示全亮
  224. *        返 回 值: 无
  225. *********************************************************************************************************
  226. */
  227. void OLED_ClrScr(uint8_t _ucMode)
  228. {
  229.         uint8_t i,j;

  230.         for (i = 0 ; i < 8; i++)
  231.         {
  232.                 for (j = 0 ; j < 128; j++)
  233.                 {
  234.                         s_ucGRAM[i][j] = _ucMode;
  235.                 }
  236.         }

  237.         if (s_ucUpdateEn == 1)
  238.         {
  239.                 OLED_BufToPanel();
  240.         }
  241. }

  242. /*
  243. *********************************************************************************************************
  244. *        函 数 名: OLED_BufToPanel
  245. *        功能说明: 将缓冲区中的点阵数据写入面板
  246. *        形    参:  无
  247. *        返 回 值: 无
  248. *********************************************************************************************************
  249. */
  250. static void OLED_BufToPanel(void)
  251. {
  252.         uint8_t i,j;

  253.         for (i = 0 ; i< 8; i++)
  254.         {
  255.                 OLED_WriteCmd (0xB0 + i);        /* 设置页地址(0~7) */
  256.                 OLED_WriteCmd (0x00);                /* 设置列地址的低地址 */
  257.                 OLED_WriteCmd (0x10);                /* 设置列地址的高地址 */

  258.                 for (j = 0 ; j < 128; j++)
  259.                 {
  260.                         OLED_WriteData(s_ucGRAM[i][j]);
  261.                 }
  262.         }
  263. }

  264. /*
  265. *********************************************************************************************************
  266. *        函 数 名: OLED_DispStr
  267. *        功能说明: 在屏幕指定坐标(左上角为0,0)显示一个字符串
  268. *        形    参:
  269. *                _usX : X坐标,对于12864屏,范围为【0 - 127】
  270. *                _usY : Y坐标,对于12864屏,范围为【0 - 63】
  271. *                _ptr  : 字符串指针
  272. *                _tFont : 字体结构体,包含颜色、背景色(支持透明)、字体代码、文字间距等参数
  273. *        返 回 值: 无
  274. *********************************************************************************************************
  275. */
  276. void OLED_DispStr(uint16_t _usX, uint16_t _usY, char *_ptr, FONT_T *_tFont)
  277. {
  278.         uint32_t i;
  279.         uint8_t code1;
  280.         uint8_t code2;
  281.         uint32_t address = 0;
  282.         uint8_t buf[32 * 32 / 8];        /* 最大支持32点阵汉字 */
  283.         uint8_t m, width;
  284.         uint8_t font_width,font_height, font_bytes;
  285.         uint16_t x, y;
  286.         const uint8_t *pAscDot;       

  287. #ifdef USE_SMALL_FONT               
  288.         const uint8_t *pHzDot;
  289. #else       
  290.         uint32_t AddrHZK;
  291. #endif       

  292.         /* 如果字体结构为空指针,则缺省按16点阵 */
  293.         if (_tFont->FontCode == FC_ST_12)
  294.         {
  295.                 font_height = 12;
  296.                 font_width = 12;
  297.                 font_bytes = 24;
  298.                 pAscDot = g_Ascii12;
  299.         #ifdef USE_SMALL_FONT               
  300.                 pHzDot = g_Hz12;
  301.         #else               
  302.                 AddrHZK = HZK12_ADDR;
  303.         #endif               
  304.         }
  305.         else
  306.         {
  307.                 /* 缺省是16点阵 */
  308.                 font_height = 16;
  309.                 font_width = 16;
  310.                 font_bytes = 32;
  311.                 pAscDot = g_Ascii16;
  312.         #ifdef USE_SMALL_FONT               
  313.                 pHzDot = g_Hz16;
  314.         #else
  315.                 AddrHZK = HZK16_ADDR;
  316.         #endif
  317.         }

  318.         /* 开始循环处理字符 */
  319.         while (*_ptr != 0)
  320.         {
  321.                 code1 = *_ptr;        /* 读取字符串数据, 该数据可能是ascii代码,也可能汉字代码的高字节 */
  322.                 if (code1 < 0x80)
  323.                 {
  324.                         /* 将ascii字符点阵复制到buf */
  325.                         memcpy(buf, &pAscDot[code1 * (font_bytes / 2)], (font_bytes / 2));
  326.                         width = font_width / 2;
  327.                 }
  328.                 else
  329.                 {
  330.                         code2 = *++_ptr;
  331.                         if (code2 == 0)
  332.                         {
  333.                                 break;
  334.                         }

  335.                         /* 计算16点阵汉字点阵地址
  336.                                 ADDRESS = [(code1-0xa1) * 94 + (code2-0xa1)] * 32
  337.                                 ;
  338.                         */
  339.                         #ifdef USE_SMALL_FONT
  340.                                 m = 0;
  341.                                 while(1)
  342.                                 {
  343.                                         address = m * (font_bytes + 2);
  344.                                         m++;
  345.                                         if ((code1 == pHzDot[address + 0]) && (code2 == pHzDot[address + 1]))
  346.                                         {
  347.                                                 address += 2;
  348.                                                 memcpy(buf, &pHzDot[address], font_bytes);
  349.                                                 break;
  350.                                         }
  351.                                         else if ((pHzDot[address + 0] == 0xFF) && (pHzDot[address + 1] == 0xFF))
  352.                                         {
  353.                                                 /* 字库搜索完毕,未找到,则填充全FF */
  354.                                                 memset(buf, 0xFF, font_bytes);
  355.                                                 break;
  356.                                         }
  357.                                 }
  358.                         #else        /* 用全字库 */
  359.                                 /* 此处需要根据字库文件存放位置进行修改 */
  360.                                 if (code1 >=0xA1 && code1 <= 0xA9 && code2 >=0xA1)
  361.                                 {
  362.                                         address = ((code1 - 0xA1) * 94 + (code2 - 0xA1)) * font_bytes + AddrHZK;
  363.                                 }
  364.                                 else if (code1 >=0xB0 && code1 <= 0xF7 && code2 >=0xA1)
  365.                                 {
  366.                                         address = ((code1 - 0xB0) * 94 + (code2 - 0xA1) + 846) * font_bytes + AddrHZK;
  367.                                 }
  368.                                 memcpy(buf, (const uint8_t *)address, font_bytes);
  369.                         #endif

  370.                                 width = font_width;
  371.                 }

  372.                 y = _usY;
  373.                 /* 开始刷LCD */
  374.                 for (m = 0; m < font_height; m++)        /* 字符高度 */
  375.                 {
  376.                         x = _usX;
  377.                         for (i = 0; i < width; i++)        /* 字符宽度 */
  378.                         {
  379.                                 if ((buf[m * ((2 * width) / font_width) + i / 8] & (0x80 >> (i % 8 ))) != 0x00)
  380.                                 {
  381.                                         OLED_PutPixel(x, y, _tFont->FrontColor);        /* 设置像素颜色为文字色 */
  382.                                 }
  383.                                 else
  384.                                 {
  385.                                         OLED_PutPixel(x, y, _tFont->BackColor);        /* 设置像素颜色为文字背景色 */
  386.                                 }

  387.                                 x++;
  388.                         }
  389.                         y++;
  390.                 }

  391.                 if (_tFont->Space > 0)
  392.                 {
  393.                         /* 如果文字底色按_tFont->usBackColor,并且字间距大于点阵的宽度,那么需要在文字之间填充(暂时未实现) */
  394.                 }
  395.                 _usX += width + _tFont->Space;        /* 列地址递增 */
  396.                 _ptr++;                        /* 指向下一个字符 */
  397.         }
  398. }

  399. /*
  400. *********************************************************************************************************
  401. *        函 数 名: OLED_PutPixel
  402. *        功能说明: 画1个像素
  403. *        形    参:
  404. *                        _usX,_usY : 像素坐标
  405. *                        _ucColor  :像素颜色
  406. *        返 回 值: 无
  407. *********************************************************************************************************
  408. */
  409. void OLED_PutPixel(uint16_t _usX, uint16_t _usY, uint8_t _ucColor)
  410. {
  411.         uint8_t ucValue;
  412.         uint8_t ucPageAddr;
  413.         uint8_t ucColAddr;

  414.         const uint8_t aOrTab[8]  = {0x01, 0x02, 0x04, 0x08,0x10,0x20,0x40,0x80};
  415.         const uint8_t aAndTab[8] = {0xFE, 0xFD, 0xFB, 0xF7,0xEF,0xDF,0xBF,0x7F};

  416.         ucPageAddr = _usY / 8;
  417.         ucColAddr = _usX;

  418.         ucValue = s_ucGRAM[ucPageAddr][ucColAddr];
  419.         if (_ucColor == 0)
  420.         {
  421.                 ucValue &= aAndTab[_usY % 8];
  422.         }
  423.         else
  424.         {
  425.                 ucValue |= aOrTab[_usY % 8];
  426.         }
  427.         s_ucGRAM[ucPageAddr][ucColAddr] = ucValue;

  428.         if (s_ucUpdateEn == 1)
  429.         {
  430.                 OLED_WriteCmd (0xB0 + ucPageAddr);                                        /* 设置页地址(0~7) */
  431.                 OLED_WriteCmd (0x00 + (ucColAddr & 0x0F));                        /* 设置列地址的低地址 */
  432.                 OLED_WriteCmd (0x10 + ((ucColAddr >> 4) & 0x0F));        /* 设置列地址的高地址 */
  433.                 OLED_WriteData(ucValue);
  434.         }
  435. }

  436. /*
  437. *********************************************************************************************************
  438. *        函 数 名: OLED_GetPixel
  439. *        功能说明: 读取1个像素
  440. *        形    参:
  441. *                        _usX,_usY : 像素坐标
  442. *        返 回 值: 颜色值 (0, 1)
  443. *********************************************************************************************************
  444. */
  445. uint8_t OLED_GetPixel(uint16_t _usX, uint16_t _usY)
  446. {
  447.         uint8_t ucValue;
  448.         uint8_t ucPageAddr;
  449.         uint8_t ucColAddr;

  450.         ucPageAddr = _usY / 8;
  451.         ucColAddr = _usX;

  452.         ucValue = s_ucGRAM[ucPageAddr][ucColAddr];
  453.         if (ucValue & (_usY % 8))
  454.         {
  455.                 return 1;
  456.         }
  457.         else
  458.         {
  459.                 return 0;
  460.         }
  461. }

  462. /*
  463. *********************************************************************************************************
  464. *        函 数 名: OLED_DrawLine
  465. *        功能说明: 采用 Bresenham 算法,在2点间画一条直线。
  466. *        形    参:
  467. *                        _usX1, _usY1 :起始点坐标
  468. *                        _usX2, _usY2 :终止点Y坐标
  469. *                        _ucColor     :颜色
  470. *        返 回 值: 无
  471. *********************************************************************************************************
  472. */
  473. void OLED_DrawLine(uint16_t _usX1 , uint16_t _usY1 , uint16_t _usX2 , uint16_t _usY2 , uint8_t _ucColor)
  474. {
  475.         int32_t dx , dy ;
  476.         int32_t tx , ty ;
  477.         int32_t inc1 , inc2 ;
  478.         int32_t d , iTag ;
  479.         int32_t x , y ;

  480.         /* 采用 Bresenham 算法,在2点间画一条直线 */

  481.         OLED_PutPixel(_usX1 , _usY1 , _ucColor);

  482.         /* 如果两点重合,结束后面的动作。*/
  483.         if ( _usX1 == _usX2 && _usY1 == _usY2 )
  484.         {
  485.                 return;
  486.         }

  487.         iTag = 0 ;
  488.         /* dx = abs ( _usX2 - _usX1 ); */
  489.         if (_usX2 >= _usX1)
  490.         {
  491.                 dx = _usX2 - _usX1;
  492.         }
  493.         else
  494.         {
  495.                 dx = _usX1 - _usX2;
  496.         }

  497.         /* dy = abs ( _usY2 - _usY1 ); */
  498.         if (_usY2 >= _usY1)
  499.         {
  500.                 dy = _usY2 - _usY1;
  501.         }
  502.         else
  503.         {
  504.                 dy = _usY1 - _usY2;
  505.         }

  506.         if ( dx < dy )   /*如果dy为计长方向,则交换纵横坐标。*/
  507.         {
  508.                 uint16_t temp;

  509.                 iTag = 1 ;
  510.                 temp = _usX1; _usX1 = _usY1; _usY1 = temp;
  511.                 temp = _usX2; _usX2 = _usY2; _usY2 = temp;
  512.                 temp = dx; dx = dy; dy = temp;
  513.         }
  514.         tx = _usX2 > _usX1 ? 1 : -1 ;    /* 确定是增1还是减1 */
  515.         ty = _usY2 > _usY1 ? 1 : -1 ;
  516.         x = _usX1 ;
  517.         y = _usY1 ;
  518.         inc1 = 2 * dy ;
  519.         inc2 = 2 * ( dy - dx );
  520.         d = inc1 - dx ;
  521.         while ( x != _usX2 )     /* 循环画点 */
  522.         {
  523.                 if ( d < 0 )
  524.                 {
  525.                         d += inc1 ;
  526.                 }
  527.                 else
  528.                 {
  529.                         y += ty ;
  530.                         d += inc2 ;
  531.                 }
  532.                 if ( iTag )
  533.                 {
  534.                         OLED_PutPixel ( y , x , _ucColor) ;
  535.                 }
  536.                 else
  537.                 {
  538.                         OLED_PutPixel ( x , y , _ucColor) ;
  539.                 }
  540.                 x += tx ;
  541.         }
  542. }

  543. /*
  544. *********************************************************************************************************
  545. *        函 数 名: OLED_DrawPoints
  546. *        功能说明: 采用 Bresenham 算法,绘制一组点,并将这些点连接起来。可用于波形显示。
  547. *        形    参:
  548. *                        x, y     :坐标数组
  549. *                        _ucColor :颜色
  550. *        返 回 值: 无
  551. *********************************************************************************************************
  552. */
  553. void OLED_DrawPoints(uint16_t *x, uint16_t *y, uint16_t _usSize, uint8_t _ucColor)
  554. {
  555.         uint16_t i;

  556.         for (i = 0 ; i < _usSize - 1; i++)
  557.         {
  558.                 OLED_DrawLine(x[i], y[i], x[i + 1], y[i + 1], _ucColor);
  559.         }
  560. }

  561. /*
  562. *********************************************************************************************************
  563. *        函 数 名: OLED_DrawRect
  564. *        功能说明: 绘制矩形。
  565. *        形    参:
  566. *                        _usX,_usY:矩形左上角的坐标
  567. *                        _usHeight :矩形的高度
  568. *                        _usWidth  :矩形的宽度
  569. *        返 回 值: 无
  570. *********************************************************************************************************
  571. */
  572. void OLED_DrawRect(uint16_t _usX, uint16_t _usY, uint8_t _usHeight, uint16_t _usWidth, uint8_t _ucColor)
  573. {
  574.         /*
  575.          ---------------->---
  576.         |(_usX,_usY)        |
  577.         V                    V  _usHeight
  578.         |                    |
  579.          ---------------->---
  580.                   _usWidth
  581.         */

  582.         OLED_DrawLine(_usX, _usY, _usX + _usWidth - 1, _usY, _ucColor);        /* 顶 */
  583.         OLED_DrawLine(_usX, _usY + _usHeight - 1, _usX + _usWidth - 1, _usY + _usHeight - 1, _ucColor);        /* 底 */

  584.         OLED_DrawLine(_usX, _usY, _usX, _usY + _usHeight - 1, _ucColor);        /* 左 */
  585.         OLED_DrawLine(_usX + _usWidth - 1, _usY, _usX + _usWidth - 1, _usY + _usHeight, _ucColor);        /* 右 */
  586. }

  587. /*
  588. *********************************************************************************************************
  589. *        函 数 名: OLED_DrawCircle
  590. *        功能说明: 绘制一个圆,笔宽为1个像素
  591. *        形    参:
  592. *                        _usX,_usY  :圆心的坐标
  593. *                        _usRadius  :圆的半径
  594. *        返 回 值: 无
  595. *********************************************************************************************************
  596. */
  597. void OLED_DrawCircle(uint16_t _usX, uint16_t _usY, uint16_t _usRadius, uint8_t _ucColor)
  598. {
  599.         int32_t  D;                        /* Decision Variable */
  600.         uint32_t  CurX;                /* 当前 X 值 */
  601.         uint32_t  CurY;                /* 当前 Y 值 */

  602.         D = 3 - (_usRadius << 1);
  603.         CurX = 0;
  604.         CurY = _usRadius;

  605.         while (CurX <= CurY)
  606.         {
  607.                 OLED_PutPixel(_usX + CurX, _usY + CurY, _ucColor);
  608.                 OLED_PutPixel(_usX + CurX, _usY - CurY, _ucColor);
  609.                 OLED_PutPixel(_usX - CurX, _usY + CurY, _ucColor);
  610.                 OLED_PutPixel(_usX - CurX, _usY - CurY, _ucColor);
  611.                 OLED_PutPixel(_usX + CurY, _usY + CurX, _ucColor);
  612.                 OLED_PutPixel(_usX + CurY, _usY - CurX, _ucColor);
  613.                 OLED_PutPixel(_usX - CurY, _usY + CurX, _ucColor);
  614.                 OLED_PutPixel(_usX - CurY, _usY - CurX, _ucColor);

  615.                 if (D < 0)
  616.                 {
  617.                         D += (CurX << 2) + 6;
  618.                 }
  619.                 else
  620.                 {
  621.                         D += ((CurX - CurY) << 2) + 10;
  622.                         CurY--;
  623.                 }
  624.                 CurX++;
  625.         }
  626. }

  627. /*
  628. *********************************************************************************************************
  629. *        函 数 名: OLED_DrawBMP
  630. *        功能说明: 在LCD上显示一个BMP位图,位图点阵扫描次序:从左到右,从上到下
  631. *        形    参:
  632. *                        _usX, _usY : 图片的坐标
  633. *                        _usHeight  :图片高度
  634. *                        _usWidth   :图片宽度
  635. *                        _ptr       :单色图片点阵指针,每个像素占用1个字节
  636. *        返 回 值: 无
  637. *********************************************************************************************************
  638. */
  639. void OLED_DrawBMP(uint16_t _usX, uint16_t _usY, uint16_t _usHeight, uint16_t _usWidth, uint8_t *_ptr)
  640. {
  641.         uint16_t x, y;

  642.         for (x = 0; x < _usWidth; x++)
  643.         {
  644.                 for (y = 0; y < _usHeight; y++)
  645.                 {
  646.                         OLED_PutPixel(_usX + x, _usY + y, *_ptr);
  647.                 }
  648.         }
  649. }

  650. /*
  651. *********************************************************************************************************
  652. *        函 数 名: OLED_ConfigGPIO
  653. *        功能说明: 配置OLED控制口线,设置为8位80XX总线控制模式或SPI模式
  654. *        形    参:  无
  655. *        返 回 值: 无
  656. *********************************************************************************************************
  657. */
  658. static void OLED_ConfigGPIO(void)
  659. {
  660.         /* 12.配置GPIO */
  661.         {
  662.                 GPIO_InitTypeDef GPIO_InitStructure;

  663.                 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

  664.                 /* 使能 FSMC, GPIOD, GPIOE, GPIOF, GPIOG 和 AFIO 时钟 */
  665.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |
  666.                                                          RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG |
  667.                                                          RCC_APB2Periph_AFIO, ENABLE);

  668.                 /* 设置 PD.00(D2), PD.01(D3), PD.04(NOE), PD.05(NWE), PD.08(D13), PD.09(D14),
  669.                  PD.10(D15), PD.14(D0), PD.15(D1) 为复用推挽输出 */
  670.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
  671.                                                                         GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
  672.                                                                         GPIO_Pin_15;
  673.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  674.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  675.                 GPIO_Init(GPIOD, &GPIO_InitStructure);

  676.                 /* 设置 PE.07(D4), PE.08(D5), PE.09(D6), PE.10(D7), PE.11(D8), PE.12(D9), PE.13(D10),
  677.                  PE.14(D11), PE.15(D12) 为复用推挽输出 */
  678.                 /* PE3,PE4 用于A19, A20, STM32F103ZE-EK(REV 1.0)必须使能 */
  679.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
  680.                                                                         GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
  681.                                                                         GPIO_Pin_15 | GPIO_Pin_3 | GPIO_Pin_4;
  682.                 GPIO_Init(GPIOE, &GPIO_InitStructure);

  683.                 /* 设置 PF.00(A0 (RS))  为复用推挽输出 */
  684.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  685.                 GPIO_Init(GPIOF, &GPIO_InitStructure);

  686.                 /* 设置 PG.12(NE4 (LCD/CS)) 为复用推挽输出 */
  687.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  688.                 GPIO_Init(GPIOG, &GPIO_InitStructure);
  689.         }

  690.         /* 2.配置FSMC总线参数 */
  691.         {
  692.                 FSMC_NORSRAMInitTypeDef  init;
  693.                 FSMC_NORSRAMTimingInitTypeDef  timing;

  694.                 /*-- FSMC Configuration ------------------------------------------------------*/
  695.                 /*----------------------- SRAM Bank 4 ----------------------------------------*/
  696.                 /* FSMC_Bank1_NORSRAM4 configuration */
  697.                 timing.FSMC_AddressSetupTime = 1;
  698.                 timing.FSMC_AddressHoldTime = 0;
  699.                 timing.FSMC_DataSetupTime = 2;
  700.                 timing.FSMC_BusTurnAroundDuration = 0;
  701.                 timing.FSMC_CLKDivision = 0;
  702.                 timing.FSMC_DataLatency = 0;
  703.                 timing.FSMC_AccessMode = FSMC_AccessMode_A;

  704.                 /*
  705.                  LCD configured as follow:
  706.                         - Data/Address MUX = Disable
  707.                         - Memory Type = SRAM
  708.                         - Data Width = 16bit
  709.                         - Write Operation = Enable
  710.                         - Extended Mode = Enable
  711.                         - Asynchronous Wait = Disable
  712.                 */
  713.                 init.FSMC_Bank = FSMC_Bank1_NORSRAM4;
  714.                 init.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
  715.                 init.FSMC_MemoryType = FSMC_MemoryType_SRAM;
  716.                 init.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
  717.                 init.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
  718.                 init.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;        /* 注意旧库无这个成员 */
  719.                 init.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
  720.                 init.FSMC_WrapMode = FSMC_WrapMode_Disable;
  721.                 init.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
  722.                 init.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
  723.                 init.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
  724.                 init.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
  725.                 init.FSMC_WriteBurst = FSMC_WriteBurst_Disable;

  726.                 init.FSMC_ReadWriteTimingStruct = &timing;
  727.                 init.FSMC_WriteTimingStruct = &timing;

  728.                 FSMC_NORSRAMInit(&init);

  729.                 /* - BANK 3 (of NOR/SRAM Bank 1~4) is enabled */
  730.                 FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
  731.         }
  732. }

  733. /*
  734. *********************************************************************************************************
  735. *        函 数 名: OLED_WriteCmd
  736. *        功能说明: 向SSD1306发送一字节命令
  737. *        形    参:  命令字
  738. *        返 回 值: 无
  739. *********************************************************************************************************
  740. */
  741. static void OLED_WriteCmd(uint8_t _ucCmd)
  742. {
  743. #ifdef OLED_SPI3_EN
  744.         uint8_t i;

  745.         SSD_CS_0();

  746.         SSD_SCK_0();
  747.         SSD_SDIN_0();        /* 0 表示后面传送的是命令 1表示后面传送的数据 */
  748.         SSD_SCK_1();

  749.         for (i = 0; i < 8; i++)
  750.         {
  751.                 if (_ucCmd & 0x80)
  752.                 {
  753.                         SSD_SDIN_1();
  754.                 }
  755.                 else
  756.                 {
  757.                         SSD_SDIN_0();
  758.                 }
  759.                 SSD_SCK_0();
  760.                 _ucCmd <<= 1;
  761.                 SSD_SCK_1();
  762.         }

  763.         SSD_CS_1();
  764. #else
  765.         OLED_CMD = _ucCmd;
  766. #endif
  767. }

  768. /*
  769. *********************************************************************************************************
  770. *        函 数 名: OLED_WriteData
  771. *        功能说明: 向SSD1306发送一字节数据
  772. *        形    参:  命令字
  773. *        返 回 值: 无
  774. *********************************************************************************************************
  775. */
  776. static void OLED_WriteData(uint8_t _ucData)
  777. {
  778. #ifdef OLED_SPI3_EN
  779.         uint8_t i;

  780.         SSD_CS_0();

  781.         SSD_SCK_0();
  782.         SSD_SDIN_1();        /* 0 表示后面传送的是命令 1表示后面传送的数据 */
  783.         SSD_SCK_1();

  784.         for (i = 0; i < 8; i++)
  785.         {
  786.                 if (_ucData & 0x80)
  787.                 {
  788.                         SSD_SDIN_1();
  789.                 }
  790.                 else
  791.                 {
  792.                         SSD_SDIN_0();
  793.                 }
  794.                 SSD_SCK_0();
  795.                 _ucData <<= 1;
  796.                 SSD_SCK_1();
  797.         }

  798.         SSD_CS_1();
  799. #else
  800.         OLED_DATA = _ucData;
  801. #endif
  802. }

  803. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
复制代码

回复

使用道具 举报

33

主题

203

回帖

302

积分

高级会员

积分
302
 楼主| 发表于 2018-10-29 08:59:01 | 显示全部楼层
eric2013 发表于 2018-10-28 02:48
没发现你的这个有什么问题,下面是我们的,SPI和FSMC均可用,用的优景。

多谢。我用的也是这个牌子的。
现在改成这样了:
void gm_set_oled_write_addr(uint8_t x, uint8_t y)
{
    gm_write_oled_command(0xb0 + y);      
    gm_write_oled_command(((2 + x) >> 4) | 0x10);
    gm_write_oled_command(((2 + x) & 0x0f)); // | | 0x02
}
似乎管用,还没完全测试,有结果了我发过来。
回复

使用道具 举报

33

主题

203

回帖

302

积分

高级会员

积分
302
 楼主| 发表于 2018-10-30 09:18:16 | 显示全部楼层
diiiiiii 发表于 2018-10-29 08:59
多谢。我用的也是这个牌子的。
现在改成这样了:
void gm_set_oled_write_addr(uint8_t x, uint8_t y)
...

测试了一下。没什么问题。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2020-3-23 18:12:20 | 显示全部楼层
eric2013 发表于 2018-10-28 02:48
没发现你的这个有什么问题,下面是我们的,SPI和FSMC均可用,用的优景。

硬汉哥,你好,请问设置偏移这条命令(0xD3)在手册里并没有找到,您是在哪里看到的呢
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
发表于 2020-3-23 18:28:51 | 显示全部楼层
cyj123456 发表于 2020-3-23 18:12
硬汉哥,你好,请问设置偏移这条命令(0xD3)在手册里并没有找到,您是在哪里看到的呢

QQ截图20200323182828.png
回复

使用道具 举报

0

主题

10

回帖

10

积分

新手上路

积分
10
发表于 2020-12-3 17:21:03 | 显示全部楼层
本帖最后由 哈哈哈哈嘻嘻 于 2020-12-3 17:46 编辑

我用的GSO1D3003,也有你同样的问题,列地址是从2开始的。但是我改成你这样后面两列显示正常了。
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-9 18:24 , Processed in 0.201192 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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