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);
}