[PSOC™] 【英飞凌PSOC 4000T DIY】驱动OLED显示屏

[复制链接]
 楼主| lulugl 发表于 2025-4-13 18:34 | 显示全部楼层 |阅读模式
<
本帖最后由 lulugl 于 2025-4-14 09:17 编辑

#申请开发板# #申请原创# #有奖活动#  @21小跑堂
【前言】
前面我分享了如何搭建基础工程:
【英飞凌PSOC 4000T DIY】进入hellowold之旅   https://bbs.21ic.com/icview-3445992-1-1.html这一篇,我将介绍如何使用CY8CPROTO-040T-MS的串行外设中的I2C外设。我前面学习到了他的串行外设下面可以实现UART、I2C、SPI三个模式,由于这款开发板的IO资源是大部分分配给了电容传器的,所以在UART与I2C分配了同样的IO,所以在开发板上还设计了一个开关SW2进行IO连接的转换。

因此在使用I2C外设时,需要把这个SW2拨到I2C的一侧,这是需要大家注意的。
当然我们也可以使用GPIO来摸拟I2C实现,但是这样就使用不到了他的I2C的一些特有功能了。
【原理图】
如果要使用它他的外设,首先需要了解他的原理图,这样才能正确的把OLED与开发板连接起来。在用户手册中,对扩展接口J24原理图:

在接口中第2脚为GND,第5脚为VCC,经测试电压为3.3可以为OLED提供工作电压。
从原理图的上得到I2C的SDA与SCL分别这P2_3,P2_2:

也与他的数据手册中的pins的复用一致的:

经过上面的分析,那下面就着手如何对他的I2C进行驱动了。
【工程移植】
1、在官方的示例库中有两个工程,分别为I2C的Master和Slave,工程:

2、我们需要驱动的的OLED屏,因此只需要master发送数据即可,所以选用i2c master这个工程做为模版工程即可。
按照前面hello world的工程创建方法,我这里创建了IIC的模版工程,创建好工程如下:


3、拿到模块代码后,首先分析一下他的I2C的工程结构,在工程中有I2C的文件,分别为I2CMaster.c与I2CSlave.c,这两个分别处理作为主、从来处理数据的文件,我们只需要发送数据给OLED所以只需要关心I2CMaster这个文件即可。
4、在master.c中,他首先创建了cy_stc_scb_i2c_master_xfer_config_t 的结构体,并把从机地址给分配为了I2C_SLAVE_ADDR,这是一个宏,因此我们需要把这个宏替换为我们的OLED屏,我这里使用的芯片为ssd1306因此,需要把宏修改为0x3C

  1. /* I2C slave address to communicate with */
  2. #define I2C_SLAVE_ADDR      (0x3c)
5、接下来在I2CMaster.c中有WritePacketToEzI2C这个函数,函数的注释如下
  1. /*******************************************************************************
  2. * Function Name: WritePacketToEzI2C
  3. ****************************************************************************//**
  4. *
  5. * Summary:
  6. *   Buffer is assigned with data to be sent to slave.
  7. *   high level PDL library function is used to control I2C SCB to send data to
  8. *   EzI2C slave. Errors are handled depend on the return value from the
  9. *   appropriate function.
  10. *
  11. * Parameters:
  12. *   writebuffer: Command packet buffer pointer
  13. *   bufferSize: Size of the packet buffer
  14. *
  15. * Return:
  16. *   Status after command is written to slave.
  17. *   TRANSFER_ERROR is returned if any error occurs.
  18. *   TRANSFER_CMPLT is returned if write is successful.
  19. *
  20. *******************************************************************************/
函数的说明非常明确,我们只需要把需要发送的writebuffer首地址,以及需要发送的地址传入就行了,返回为两个状态,即为TRANSFER_ERROR或者传感完成TRANSFER_CMPLT。
经过上面的从机地址的指定,以及I2C发送数据的功能函数后,我们就可以来实现我们OLED的代码了。
6、在工程的source文件夹下添加两个文件一个为ssd1306_driver.h以及ssd1306_driver.c,编写OLED的发送命令与发送数据的函数:
  1. // 发送命令到 SSD1306
  2. void ssd1306_send_command(uint8_t command) {
  3.     uint8_t buffer[2] = {SSD1306_COMMAND_MODE, command};
  4.     WritePacketToEzI2C(buffer, 2);
  5. }

  6. // 发送数据到 SSD1306
  7. void ssd1306_send_data(uint8_t data) {
  8.     uint8_t buffer[2] = {SSD1306_DATA_MODE, data};
  9.     WritePacketToEzI2C(buffer, 2);
  10. }
基实移植OLED就是修改以上的两个函数,即可完成。整体代码如下:
  1. /*
  2. * ssd1306_driver.c
  3. *
  4. *  Created on: 2025年4月13日
  5. *      Author: liujianhua
  6. */

  7. #include "cy_pdl.h"
  8. #include "cybsp.h"
  9. #include "I2CMaster.h"

  10. #define SSD1306_I2C_ADDRESS 0x3C
  11. #define SSD1306_WIDTH 128
  12. #define SSD1306_HEIGHT 64

  13. #define SSD1306_COMMAND_MODE 0x00
  14. #define SSD1306_DATA_MODE 0x40

  15. #define TRANSFER_ERROR 0


  16. // 发送命令到 SSD1306
  17. void ssd1306_send_command(uint8_t command) {
  18.     uint8_t buffer[2] = {SSD1306_COMMAND_MODE, command};
  19.     WritePacketToEzI2C(buffer, 2);
  20. }

  21. // 发送数据到 SSD1306
  22. void ssd1306_send_data(uint8_t data) {
  23.     uint8_t buffer[2] = {SSD1306_DATA_MODE, data};
  24.     WritePacketToEzI2C(buffer, 2);
  25. }

  26. // 初始化 SSD1306
  27. void ssd1306_init() {
  28.     // 复位 OLED

  29.     Cy_SysLib_Delay(1); // 短暂延时

  30.     // 发送初始化命令
  31.     ssd1306_send_command(0xAE); // 关闭显示
  32.     ssd1306_send_command(0xD5); // 设置显示时钟分频比/振荡器频率
  33.     ssd1306_send_command(0x80);
  34.     ssd1306_send_command(0xA8); // 设置多路复用率
  35.     ssd1306_send_command(0x3F);
  36.     ssd1306_send_command(0xD3); // 设置显示偏移
  37.     ssd1306_send_command(0x00);
  38.     ssd1306_send_command(0x40); // 设置显示开始行
  39.     ssd1306_send_command(0x8D); // 电荷泵设置
  40.     ssd1306_send_command(0x14);
  41.     ssd1306_send_command(0x20); // 设置内存寻址模式
  42.     ssd1306_send_command(0x00);
  43.     ssd1306_send_command(0xA1); // 设置段重映射
  44.     ssd1306_send_command(0xC8); // 设置 COM 输出扫描方向
  45.     ssd1306_send_command(0xDA); // 设置 COM 引脚硬件配置
  46.     ssd1306_send_command(0x12);
  47.     ssd1306_send_command(0x81); // 设置对比度控制
  48.     ssd1306_send_command(0xCF);
  49.     ssd1306_send_command(0xD9); // 设置预充电周期
  50.     ssd1306_send_command(0xF1);
  51.     ssd1306_send_command(0xDB); // 设置 VCOMH 取消选择级别
  52.     ssd1306_send_command(0x40);
  53.     ssd1306_send_command(0xA4); // 全局显示开启
  54.     ssd1306_send_command(0xA6); // 设置正常显示
  55.     ssd1306_send_command(0xAF); // 开启显示
  56. }

  57. // 清屏
  58. void ssd1306_clear_screen(uint8_t mode) {
  59.     for (uint8_t page = 0; page < 8; page++) {
  60.         ssd1306_send_command(0xB0 | page); // 设置页地址
  61.         ssd1306_send_command(0x00); // 设置列低地址
  62.         ssd1306_send_command(0x10); // 设置列高地址
  63.         for (uint8_t col = 0; col < SSD1306_WIDTH; col++) {
  64.             ssd1306_send_data(mode);
  65.         }
  66.     }
  67. }
程序中,我添加了一个用于清展的函数,传于Mode来实现对整个屏的刷新。
7、在ssd1306_driver.h中把供用户使用的两个函数定义好即可:
  1. /*
  2. * ssd1306_driver.h
  3. *
  4. *  Created on: 2025年4月13日
  5. *      Author: liujianhua
  6. */

  7. #ifndef SOURCE_SSD1306_DRIVER_H_
  8. #define SOURCE_SSD1306_DRIVER_H_

  9. void ssd1306_init();
  10. void ssd1306_clear_screen(uint8_t mode);



  11. #endif /* SOURCE_SSD1306_DRIVER_H_ */
8、接下来在Main主函数中添加测试代码,在工程中模版中已有i2c_marster_init了,所以我们只需要添加oled的测试函数即可,整体代码如下:

  1. /* Header file includes */
  2. #include "cy_pdl.h"
  3. #include "cybsp.h"
  4. #include "I2CMaster.h"
  5. #include "I2CSlave.h"
  6. #include "ssd1306_driver.h"

  7. /*******************************************************************************
  8. * Macros
  9. *******************************************************************************/
  10. /* LED Status */
  11. #define OFF                     CYBSP_LED_STATE_OFF
  12. #define ON                      CYBSP_LED_STATE_ON

  13. /* Delay duration */
  14. #define CMD_TO_CMD_DELAY        (1000UL)

  15. int main(void)
  16. {
  17.     cy_rslt_t result;

  18.     /* Initialize the device and board peripherals */
  19.     result = cybsp_init() ;
  20.     if (result != CY_RSLT_SUCCESS)
  21.     {
  22.         CY_ASSERT(0);
  23.     }

  24.     status = initMaster();
  25.     if(status != I2C_SUCCESS)
  26.     {
  27.         handle_error();
  28.     }

  29.     /* Enable interrupts */
  30.     __enable_irq();
  31.     ssd1306_init();  //初始化oled

  32.     for(;;)
  33.     {

  34.             ssd1306_clear_screen(0);  //全屏黑
  35.             Cy_SysLib_Delay(CMD_TO_CMD_DELAY);
  36.             ssd1306_clear_screen(0xFF);  //全屏白
  37.             Cy_SysLib_Delay(CMD_TO_CMD_DELAY);
  38.             Cy_GPIO_Inv(CYBSP_USER_LED1_PORT, CYBSP_USER_LED1_PIN);
  39.     }
  40. }

  41. /* [] END OF FILE */
【测试效果】
编译后下载到开发板,按上面的原理图将OLED与开发板连接起来。然后我们就看OLED屏交规刷新了:

【总结】
ModusToolbox提供好了非常好的外设模版,我们在使用他的外设时,非常方便的就能实现即定功能。当然这只是一个初步的测试,还没有将有可能错误发生的进行处理。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
Amazingxixixi 发表于 2025-4-24 17:40 | 显示全部楼层
学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

180

主题

830

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部

180

主题

830

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部