SPI代码实现-OLED屏幕

1. 实现软件SPI

1.1. 驱动层:

关注的点:

1.1.1. 向SSD1306写入一个字节。

//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)//0xAE 0
{
    u8 i;
    if(cmd)
        OLED_DC_Set();
    else
        OLED_DC_Clr();
//    //拉低片选,开始通信
    OLED_CS_Clr();

//    for(i=0; i<8; i++)
//    {
//        OLED_SCL_Clr();
		__NOP();__NOP();
//        if(dat&0x80)
//            OLED_SDA_Set();
//        else
//            OLED_SDA_Clr();

//        OLED_SCL_H();
//        dat<<=1;
//    }
//    //结束之后需要把SCL拉低
//    OLED_SCL_Clr();
//    //拉高片选,通信结束
//    OLED_CS_Set();

//    OLED_DC_Set();

	bsp_soft_spi_write(dat);
	//拉高片选,通信结束	
	OLED_CS_Set();
	
	//拉高DC引脚
	OLED_DC_Set();   	
}

1.1.2. 送指令到晶联讯字库IC

//送指令到晶联讯字库IC
void Send_Command_to_ROM(u8 dat)
{
//    u8 i;
//    for(i=0; i<8; i++)
//    {
//        OLED_SCL_Clr();
//        if(dat&0x80)
//        {
//            OLED_SDA_Set();
//        }
//        else
//        {
//            OLED_SDA_Clr();
//        }
//        dat<<=1;
//        OLED_SCL_H();
//    }
//    //拉低时钟
//    OLED_SCL_Clr();
	
	
	 bsp_soft_spi_write(dat);
}

1.1.3. 从晶联讯字库IC中取汉字或字符数据(1个字节)

//从晶联讯字库IC中取汉字或字符数据(1个字节)
u8 Get_data_from_ROM(void)
{
//    u8 i,read=0;
//    for(i=0; i<8; i++)
//    {
//        OLED_SCL_Clr();
//        read<<=1;
//        if(OLED_READ_FS0())
//        {
//            read++;
//        }
//        OLED_SCL_H();
//    }
//    //拉低时钟
//    OLED_SCL_Clr();
//    return read;
	return bsp_soft_spi_read();
}

1.1.4. OLED初始化

//OLED的初始化
void OLED_Init(void)
{
    //DC:PB8
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);


    //CS1:PA15
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_15);


    //CS2:PA4
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);

    //GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);
    //拉高所有的输出引脚
    //OLED_SCL_H();
    OLED_SDA_Set();
    OLED_DC_Set();
    //两个片选需要拉高
    OLED_ROM_CS_Set();

    delay_1ms(200);

    OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
    OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
    OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
    OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
    OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
    OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
    OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
    OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WR_Byte(0x00,OLED_CMD);//-not offset
    OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
    OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
    OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
    OLED_WR_Byte(0x12,OLED_CMD);
    OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
    OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
    OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WR_Byte(0x02,OLED_CMD);//
    OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
    OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
    OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
    OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
    OLED_Clear();
    OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}

1.2. 应用层:

#ifndef	_BSP_SOFT_SPI_H
#define _BSP_SOFT_SPI_H

#include "gd32f4xx.h"
#include "oled.h"

//SCL:PB3
#define SPI_SCL_RCU  RCU_GPIOB
#define SPI_SCL_PORT GPIOB
#define SPI_SCL_PIN  GPIO_PIN_3 
//MOSI:PB5
#define SPI_MOSI_RCU  RCU_GPIOB
#define SPI_MOSI_PORT GPIOB
#define SPI_MOSI_PIN  GPIO_PIN_5 

//FSO(MISO):PB4
#define SPI_MISO_RCU  RCU_GPIOB
#define SPI_MISO_PORT GPIOB
#define SPI_MISO_PIN  GPIO_PIN_4 

//FS0(MISO) 	PB4	     
#define OLED_READ_FS0()    gpio_input_bit_get(GPIOB,GPIO_PIN_4)//SCL
//SCL	PB3
#define OLED_SCL_Clr() gpio_bit_reset(GPIOB,GPIO_PIN_3)
#define OLED_SCL_H() gpio_bit_set(GPIOB,GPIO_PIN_3)
//MOSI	PB5
#define OLED_SDA_Clr() gpio_bit_reset(GPIOB,GPIO_PIN_5)
#define OLED_SDA_Set() gpio_bit_set(GPIOB,GPIO_PIN_5)

//初始化
void bsp_soft_spi_config();

//写入
void bsp_soft_spi_write(u8 dat);

//读取
u8 bsp_soft_spi_read();

#endif

#include "bsp_soft_spi.h"

//初始化
void bsp_soft_spi_config(){
	//SCL:PB3
	rcu_periph_clock_enable(SPI_SCL_RCU);
	gpio_mode_set(SPI_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI_SCL_PIN);
	gpio_output_options_set(SPI_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SPI_SCL_PIN);

	//MOSI:PB5
	rcu_periph_clock_enable(SPI_MOSI_RCU);
	gpio_mode_set(SPI_MOSI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI_MOSI_PIN);
	gpio_output_options_set(SPI_MOSI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SPI_MOSI_PIN);

	//FSO(MISO):PB4
	rcu_periph_clock_enable(SPI_MISO_RCU);
	gpio_mode_set(SPI_MISO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SPI_MISO_PIN);
	//拉高
	OLED_SDA_Set();
	
}

//写入
void bsp_soft_spi_write(u8 dat){
    for(uint8_t i=0; i<8; i++)
    {
        OLED_SCL_Clr();

        if(dat&0x80)
            OLED_SDA_Set();
        else
            OLED_SDA_Clr();

        OLED_SCL_H();
        dat<<=1;
    }
    //结束之后需要把SCL拉低
    OLED_SCL_H();

}

//读取
u8 bsp_soft_spi_read(){
	
	u8 i,read=0;
    for(i=0; i<8; i++)
    {
        OLED_SCL_Clr();
        read<<=1;
        if(OLED_READ_FS0())
        {
            read++;
        }
        OLED_SCL_H();
    }
    //拉低时钟
    OLED_SCL_Clr();
    return read;
	
}

2. 硬件实现SPI

2.1. gpio引脚初始化

/*****************spi引脚的GPIO初始化********************/
    //SCL:PB3
    rcu_periph_clock_enable(SPI_SCL_RCU);
    gpio_mode_set(SPI_SCL_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI_SCL_PIN);
    gpio_output_options_set(SPI_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SPI_SCL_PIN);

    gpio_af_set(SPI_SCL_PORT,GPIO_AF_5,SPI_SCL_PIN);


    //MOSI:PB5
    rcu_periph_clock_enable(SPI_MOSI_RCU);
    gpio_mode_set(SPI_MOSI_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI_MOSI_PIN);
    gpio_output_options_set(SPI_MOSI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SPI_MOSI_PIN);
    gpio_af_set(SPI_MOSI_PORT,GPIO_AF_5,SPI_MOSI_PIN);

    //FSO(MISO):PB4
    rcu_periph_clock_enable(SPI_MISO_RCU);
    gpio_mode_set(SPI_MISO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, SPI_MISO_PIN);
    gpio_output_options_set(SPI_MISO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, SPI_MISO_PIN);
    gpio_af_set(SPI_MISO_PORT,GPIO_AF_5,SPI_MISO_PIN);

2.2. 需要配置的外设初始化

2.3. 写和读

2.3.1. 写

判断TBE和RBNE的标志位是否为0

代码逻辑描述:

先判断标志位TEB,发送缓冲区的数据是否为0(空),为1(非空)的话就一直做while循环,等待为空。

为空之后,调用spi_i2s_data_transmit,缓冲区发送数据。

再判断标志位RBNE,接收缓冲区的数据是否为0(空),为1(非空)的话就一直做while循环,等待为空。

为空的话,调用spi_i2s_data_receive方法,接收数据

//写入
void bsp_hard_spi_write(u8 dat) {
	//等待发送缓冲区为空
    while(RESET == spi_i2s_flag_get(SPI_HARD_NUM,SPI_FLAG_TBE)) {};
    spi_i2s_data_transmit(SPI_HARD_NUM,dat);
	//需要处理另外读取线路
    while(RESET == spi_i2s_flag_get(SPI_HARD_NUM,SPI_FLAG_RBNE)) {};
    spi_i2s_data_receive(SPI_HARD_NUM);
}

2.3.2. 读

//读取
u8 bsp_hard_spi_read() {
	//读取也需要写入(生成时钟信号)
    while(RESET == spi_i2s_flag_get(SPI_HARD_NUM, SPI_FLAG_TBE)) {};
    spi_i2s_data_transmit(SPI_HARD_NUM, 0x00);
	//需要处理另外读取线路
    while(RESET == spi_i2s_flag_get(SPI_HARD_NUM, SPI_FLAG_RBNE)) {};
    return spi_i2s_data_receive(SPI_HARD_NUM);
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值