[原创] 【年终回炉:ST NUCLEO-U083RC】+SPI点亮OLED屏应用测试

流水源   2026-3-24 22:38 楼主

本次来试试SPI功能。使用手上SPI接口的oled来试一试。

首先还是打开STM32CUBEMX来配置SPI接口。

image.png  

OLED接口使用SPI1,PA5,PA6,PA7。

片选使用PB6,DC脚使用PC7,复位脚使用PA9。

image.png  

image.png  

下面是编写代码,OLED的spi接口驱动如下

#include "main.h"
#include "drv_spi.h"




void    drv_spi_gpio_init( void )
{

}


/**
 * SSIOF callback function
 *
 * @param[in]   dataCnt     Count of writing
 * @param[in]   errStatus   Status of operation result
 * [url=home.php?mod=space&uid=784970]@return[/url] None
 */
typedef  void (*CallbackHook)(void);
volatile uint32_t spi_transmit_ok;
CallbackHook    spi_cmpl_fn = NULL;


extern SPI_HandleTypeDef hspi1;
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi->Instance == SPI1)
    {
    }
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi->Instance == SPI1)
    {
        spi_transmit_ok = 1;
        if(spi_cmpl_fn != NULL)    spi_cmpl_fn();
    }
}

///////////////////////////////////////////////////////////////////////////////////////
uint8_t spi_transmit_byte(void *spibus,uint8_t ch)
{
    uint8_t txbuf,rxbuf;
    
    txbuf = ch;
    rxbuf = 0xff;
    spi_transmit_ok = 0;
    spi_cmpl_fn = NULL;
    
    HAL_SPI_TransmitReceive(&hspi1,(void *)&txbuf, (void *)&rxbuf, 1, 10);
    return rxbuf;
}

uint8_t spi_transmit_buff(void *spibus,uint8_t * wbuf,uint8_t * rbuf,uint32_t len,void(* callback)(void))
{
    spi_transmit_ok = 0;
    spi_cmpl_fn = callback;
    HAL_SPI_TransmitReceive_DMA(&hspi1,wbuf, rbuf, len);
    if(callback == NULL)
    {
        while(!spi_transmit_ok);
    }
    return 0;
}


void spi_write_read_buff(void *spibus,uint8_t * wbuf,uint32_t wl,uint8_t * rbuf,uint32_t rl)
{
    if((wbuf != NULL) && (wl != 0))
    {
        spi_transmit_ok = 0;
        spi_cmpl_fn = NULL;
        HAL_SPI_Transmit(&hspi1,wbuf, wl, 100);
    }

    if((rbuf != NULL) && (rl != 0))
    {
        memset(rbuf,0,rl);
        spi_transmit_ok = 0;
        spi_cmpl_fn = NULL;
        HAL_SPI_Receive(&hspi1,rbuf, rl, 100);
    }
}


#include <main.h>

// Choose a bus
//#define SSD1306_USE_I2C
#define SSD1306_USE_SPI


#ifdef  SSD1306_USE_I2C
#include "drv_i2c.h"
#define SSD1306_I2C_NUM         0

#define SSD1306_I2C_ADDR        (0x3C)

#endif

#ifdef  SSD1306_USE_SPI
#include "drv_spi.h"
#define SSD1306_SPI_NUM             0

#define SSD1306_RST_Set()           HAL_GPIO_WritePin(LCD_BLK_GPIO_Port,LCD_BLK_Pin,GPIO_PIN_SET)
#define SSD1306_RST_Reset()         HAL_GPIO_WritePin(LCD_BLK_GPIO_Port,LCD_BLK_Pin,GPIO_PIN_RESET)

#define SSD1306_DC_Set()            HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_SET)
#define SSD1306_DC_Reset()          HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_RESET)

#define SSD1306_SPI_CS_Set()        HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET)
#define SSD1306_SPI_CS_Reset()      HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET)


#endif

#define ssd1306_mdelay(x)      delay_ms(x)


#if defined(SSD1306_USE_SPI)
void ssd1306_Reset(void) 
{
    SSD1306_SPI_CS_Set();
    // Reset the OLED
    SSD1306_RST_Reset();
    ssd1306_mdelay(10);
    SSD1306_RST_Set();
    ssd1306_mdelay(10);
}

// Send a byte to the command register
void ssd1306_WriteCommand(uint8_t byte) 
{
    SSD1306_SPI_CS_Reset(); // select OLED
    SSD1306_DC_Reset();     // command
    spi_transmit_byte(SSD1306_SPI_NUM, byte);
    SSD1306_SPI_CS_Set();   // un-select OLED
}

// Send data
void ssd1306_WriteData(uint8_t* buffer, size_t buff_size) 
{
    SSD1306_SPI_CS_Reset(); // select OLED
    SSD1306_DC_Set();     // command
    spi_write_read_buff(SSD1306_SPI_NUM, buffer, buff_size,NULL,0);
    SSD1306_SPI_CS_Set();   // un-select OLED
}

#else
#error "You should define SSD1306_USE_SPI or SSD1306_USE_I2C macro"
#endif


uint8_t SSD1306_Buffer[SSD1306_BUFFER_SIZE];

void ssd1306_SetContrast(const uint8_t value)
{
    const uint8_t kSetContrastControlRegister = 0x81;
    ssd1306_WriteCommand(kSetContrastControlRegister);
    ssd1306_WriteCommand(value);
}

uint32_t ssd1306_SetDisplayOn(uint8_t light)
{
    if (light)
    {
        ssd1306_WriteCommand(0x8D); //--set DC-DC enable
        ssd1306_WriteCommand(0x14); //
        ssd1306_WriteCommand(0xAF);// Display on
    }else 
    {
        ssd1306_WriteCommand(0x8D); //--set DC-DC enable
        ssd1306_WriteCommand(0x10); //
        ssd1306_WriteCommand(0xAE);// Display off
    }
    return 0;
}


// Initialize the oled screen
uint32_t ssd1306_Init(void *args) 
{
#if defined(SSD1306_USE_I2C)
    I2C_BUS_DEV = I2C_FindDevice(I2C_NAME); 
    if (I2C_BUS_DEV == NULL)
    {
        return -1;
    }
#endif
    
#if defined(SSD1306_USE_SPI)

#endif

    // Reset OLED
    ssd1306_Reset();
    // Wait for the screen to boot
    ssd1306_mdelay(100);
    // Init OLED
    ssd1306_SetDisplayOn(0); //display off

    ssd1306_WriteCommand(0x20); //Set Memory Addressing Mode
    ssd1306_WriteCommand(0x00); // 00b,Horizontal Addressing Mode; 01b,Vertical Addressing Mode;
                                // 10b,Page Addressing Mode (RESET); 11b,Invalid
    ssd1306_WriteCommand(0xB0); //Set Page Start Address for Page Addressing Mode,0-7

#ifdef SSD1306_MIRROR_VERT
    ssd1306_WriteCommand(0xC0); // Mirror vertically
#else
    ssd1306_WriteCommand(0xC8); //Set COM Output Scan Direction
#endif

    ssd1306_WriteCommand(0x00); //---set low column address
    ssd1306_WriteCommand(0x10); //---set high column address

    ssd1306_WriteCommand(0x40); //--set start line address - CHECK

    ssd1306_SetContrast(0xFF);

#ifdef SSD1306_MIRROR_HORIZ
    ssd1306_WriteCommand(0xA0); // Mirror horizontally
#else
    ssd1306_WriteCommand(0xA1); //--set segment re-map 0 to 127 - CHECK
#endif

#ifdef SSD1306_INVERSE_COLOR
    ssd1306_WriteCommand(0xA7); //--set inverse color
#else
    ssd1306_WriteCommand(0xA6); //--set normal color
#endif

// Set multiplex ratio.
#if (SSD1306_HEIGHT == 128)
    // Found in the Luma Python lib for SH1106.
    ssd1306_WriteCommand(0xFF);
#else
    ssd1306_WriteCommand(0xA8); //--set multiplex ratio(1 to 64) - CHECK
#endif

#if (SSD1306_HEIGHT == 32)
    ssd1306_WriteCommand(0x1F); //
#elif (SSD1306_HEIGHT == 64)
    ssd1306_WriteCommand(0x3F); //
#elif (SSD1306_HEIGHT == 128)
    ssd1306_WriteCommand(0x3F); // Seems to work for 128px high displays too.
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif

    ssd1306_WriteCommand(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content

    ssd1306_WriteCommand(0xD3); //-set display offset - CHECK
    ssd1306_WriteCommand(0x00); //-not offset

    ssd1306_WriteCommand(0xD5); //--set display clock divide ratio/oscillator frequency
    ssd1306_WriteCommand(0xF0); //--set divide ratio

    ssd1306_WriteCommand(0xD9); //--set pre-charge period
    ssd1306_WriteCommand(0x22); //

    ssd1306_WriteCommand(0xDA); //--set com pins hardware configuration - CHECK
#if (SSD1306_HEIGHT == 32)
    ssd1306_WriteCommand(0x02);
#elif (SSD1306_HEIGHT == 64)
    ssd1306_WriteCommand(0x12);
#elif (SSD1306_HEIGHT == 128)
    ssd1306_WriteCommand(0x12);
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif

    ssd1306_WriteCommand(0xDB); //--set vcomh
    ssd1306_WriteCommand(0x20); //0x20,0.77xVcc

    ssd1306_SetDisplayOn(1); //--turn on SSD1306 panel
    
    return 0;
}

整个工程如图:

image.png   下面是测试oled显示代码:

image.png

最终编译下载之后就可以看到oled显示字符。

image.png   image.png   image.png  

这里顺便移植了一个qrcode显示。

image.png  

image.png  

 工程代码:

STM32U083_Demo.zip (9.31 MB)
(下载次数: 0, 昨天 22:38 上传)

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复