[GD32L233C-START 评测] 第六篇 SPI 的应用-OLED显示

xiaoli2018   2022-2-10 14:23 楼主

oled.gif

SPI的用法比I2C的用法简单很多,没有START和STOP之类的起始字节和结束字节,主从机之间也不用通过ACK进行确认。

这是因为SPI与I2C的通信机制不同。SPI的主从机是确定的,主机通过CS线选择不同的从机进行通信。而I2C没有CS线,主从机的确定只能通过I2C的通信机制。

SPI的使用主要包括以下两部分:

  • 初始化
  • 读写操作

初始化

SPI的初始化包括:

  • 时钟:使能引脚和SPI的时钟
  • 引脚:引脚初始化和设置为复用功能
  • SPI类型:设置通信方式、波形时序频率
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);

    gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

    spi_parameter_struct spi_init_struct;
    spi_i2s_deinit(SPI1);
    spi_struct_para_init(&spi_init_struct);

    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_32;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    spi_enable(SPI1);

SPI的读写操作

读写函数包括:

  • void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data);
  • uint16_t spi_i2s_data_receive(uint32_t spi_periph);

注意在发送数据的时候,每次发送之前要检测标志位SPI_FLAG_TBE是否置位,这个标志位表示发送缓冲区空,可以向发送缓冲区写入新的数据了。而发送完成需要检测SPI_FLAG_TRANS置位,这个标志位表示通信是否在进行中。

SPI的应用-使用SPI接口操作OLED屏

oled的驱动函数实际上只需要修改一个函数,void OLED_WR_Byte(uint8_t dat,uint8_t cmd)。这个函数负责向OLED写入数据或指令。其它部分可以直接使用厂家给出的测试代码。但是一定要注意,在发送完数据之后,一定要检查SPI_FLAG_TRANS置位之后在拉高CS线。

一开始我改了代码之后屏幕始终没有输出,但是用IO模拟SPI就可以在屏幕上显示,这个就是因为在拉高CS线之前没有检查SPI_FLAG_TRANS置位,造成数据还没有发送完就中断了数据的发送。

void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{			  
    if(cmd)
      gpio_bit_set(OLED_DC_PORT,OLED_DC_PIN);
    else 
      gpio_bit_reset(OLED_DC_PORT,OLED_DC_PIN);

    gpio_bit_reset(OLED_CS_PORT,OLED_CS_PIN);

    while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));

    spi_i2s_data_transmit(SPI1,dat);
    
    while(RESET != spi_i2s_flag_get(SPI1, SPI_FLAG_TRANS));
    //注意在拉高CS线之前一定要等待TRANS标志位置位
    gpio_bit_set(OLED_CS_PORT,OLED_CS_PIN);
    gpio_bit_set(OLED_DC_PORT,OLED_DC_PIN);   
} 

 

回复评论

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