当前位置: 首页 > news >正文

GPIO 模拟SPI

GPIO 模拟SPI

  • SPI简介
    • SCPH=0,SCPOL=0 的 SPI 协议时序图![在这里插入图片描述](https://img-blog.csdnimg.cn/daeedeab80d14239aa1331736b17bf7d.png)
    • SCPH=1,SCPOL=0 的 SPI 协议时序图
    • SCPH=0,SCPOL=1 的 SPI 协议时序图
    • SCPH=1,SCPOL=1 的 SPI 协议时序图
  • GPIO模拟
    • 定义出MISO、MOSI、CS、CLK等
    • 往从设备发送数据
    • 从设备读取数据
  • stm32上完整demo

SPI简介

SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。

  • SDO(MOSI): 主设备数据输出,从设备数据输入
  • SDI(MISO):主设备数据输入,从设备数据输出
  • SCLK : 时钟信号,由主设备产生
  • CS :从设备使能信号,由主设备控制

SCPH=0,SCPOL=0 的 SPI 协议时序图在这里插入图片描述

SCPH=1,SCPOL=0 的 SPI 协议时序图

在这里插入图片描述

SCPH=0,SCPOL=1 的 SPI 协议时序图

在这里插入图片描述

SCPH=1,SCPOL=1 的 SPI 协议时序图

在这里插入图片描述

GPIO模拟

定义出MISO、MOSI、CS、CLK等

#define CS_GPIO                       (0)
#define CLK_GPIO                      (1)
#define MOSI_GPIO                     (2)
#define MISO_GPIO                     (3)
#define IRQ_GPIO                      (4)

#define CS(a)                         Set_SPI_Related_Gpio(a, CS_GPIO)
#define DCLK(a)                       Set_SPI_Related_Gpio(a, CLK_GPIO)
#define DIN(a)                        Set_SPI_Related_Gpio(a, MOSI_GPIO)
#define DOUT()                        Get_SPI_Related_Gpio(MISO_GPIO)

往从设备发送数据

/**
  * @brief  Write Byte to LCD
  * @param  byte : Byte
  */
void WriteByteSPI(unsigned char byte)
{
    unsigned char buf;
    unsigned char i;
    CS(0);
    for(i=0;i<8;i++) 
    {
        buf=(byte>>(7-i))&0x1;
        DIN(buf);
        DCLK(0);
        DCLK(1);
    }	
    CS(1);
}

从设备读取数据

/**
  * @brief  Read data from spi
  */
static unsigned short ReadByteSPI(void) 
{
    unsigned short buf=0,temp;
    unsigned char i;
    uint level = 0;
    DIN(0);
    DCLK(1);
    CS(0);
    for(i=0;i<8;i++)
    {
        DCLK(0);
        level = DOUT();
        temp= (level) ? 1:0;
        buf|=(temp<<(7-i));
        //Delayus(5);
        DCLK(0);
        DCLK(1);
    }
    CS(1);
    buf&=0xff;
    return(buf);
}

stm32上完整demo

//LCD.h
#include "HAL_conf.h"

#define SPI_CS(a)	\
						if (a)	\
						GPIOA->BSRR = GPIO_Pin_4;	\
						else		\
						GPIOA->BRR = GPIO_Pin_4;
#define SPI_DCLK(a)	\
						if (a)	\
						GPIOA->BSRR = GPIO_Pin_5;	\
						else		\
						GPIOA->BRR = GPIO_Pin_5;
#define SPI_SDA(a)	\
						if (a)	\
						GPIOA->BSRR = GPIO_Pin_7;	\
						else		\
						GPIOA->BRR = GPIO_Pin_7;
#define lcd_RS(a)	\
						if (a)	\
						GPIOA->BSRR = GPIO_Pin_3;	\
						else		\
						GPIOA->BRR = GPIO_Pin_3;

#define WHITE						0xFFFF
#define BLACK						0x0000	  
#define BLUE						0x001F  
#define BRED						0XF81F
#define GRED						0XFFE0
#define GBLUE						0X07FF
#define RED							0xF800
#define MAGENTA						0xF81F
#define GREEN						0x07E0
#define CYAN						0x7FFF
#define YELLOW						0xFFE0
#define BROWN						0XBC40 //棕色
#define BRRED						0XFC07 //棕红色
#define GRAY						0X8430 //灰色

void LCD_Initial(void); //LCD初始化函数
void Delayms(unsigned short time);
void LCD_WriteRegIndex(unsigned char Index);
void LCD_WriteData(unsigned short dat);
void LCD_WR_REG(u16 Index,u16 CongfigTemp);
void Lcd_SetCursor(u16 x,u16 y);
void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend);
void SPILCD_DrawPoint(unsigned short x,unsigned short y,unsigned short color);
void SPILCD_Clear(unsigned short Color);
void SPILCD_Clear_Fast(unsigned char single_Color);
void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color);
void SPILCD_DrawLine(unsigned short x1,unsigned short y1,unsigned short x2,unsigned short y2,unsigned short color);
void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag) ;
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag);
void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic);

//LCD.c
#include "LCD.h"
#include "ASCII.h"
#include "GB1616.h"	//16*16汉字字模
#define SPILCD_W 176
#define SPILCD_H 220

void Delayms(unsigned short time)  //延时函数
{
	unsigned short i,j;
	for(i=0;i<time;i++)
		for(j=0;j<5000;j++)	;
}

void LCD_WriteByteSPI(unsigned char byte) //SPI模拟函数,写一个8bit的数据
{
	  unsigned char buf;
    unsigned char i;
    for(i=0;i<8;i++) 
    {
        buf=(byte>>(7-i))&0x1;
        SPI_SDA(buf);
				SPI_DCLK(0);
        SPI_DCLK(1);
    }	
}
void LCD_WriteoneSPI(unsigned char byte) //写一个4bit的数据
{
	  unsigned char buf;
    unsigned char i;
	
    for(i=0;i<4;i++) 
    {
        buf=(byte>>(3-i))&0x1;
        SPI_SDA(buf);
				SPI_DCLK(0);
        SPI_DCLK(1);
    }	

}
void WriteComm(unsigned char dat) //写命令
{
//	SPI_CS(0);
	lcd_RS(0);
	LCD_WriteByteSPI(dat);	
	lcd_RS(1);
//	SPI_CS(1);
}
void LCD_WriteRegIndex(unsigned char Index) //写命令的参数
{
	lcd_RS(0);
	LCD_WriteByteSPI(Index);
	lcd_RS(1);
}
void LCD_WriteData(unsigned short dat) //写数据
{
  LCD_WriteByteSPI(dat>>8);		//	start byte RS=1,RW=0----Write a GRAM data
  LCD_WriteByteSPI(dat);
}
/******************************************
函数名:Lcd写命令函数
功能:向Lcd指定位置写入应有命令或数据
入口参数:Index 要寻址的寄存器地址
          ConfigTemp 写入的数据或命令值
******************************************/
void LCD_WR_REG(u16 Index,u16 CongfigTemp)
{
	LCD_WriteRegIndex(Index);
	LCD_WriteByteSPI(CongfigTemp);
//LCD_WriteData(CongfigTemp);
}

void LCD_Initial(void) //LCD初始化函数
{

	GPIO_SetBits(GPIOA, GPIO_Pin_2);//打开背光

		//Power Voltage Setting 
LCD_WR_REG(0x1A,0x02);     //BT 
LCD_WR_REG(0x1B,0x88);     //VRH 
 
//****VCOM offset**/// 
LCD_WR_REG(0x23,0x00);     //SEL_VCM 
LCD_WR_REG(0x24,0xEE);     //VCM 
LCD_WR_REG(0x25,0x15);     //VDV 
 
LCD_WR_REG(0x2D,0x03);     //NOW[2:0]=011 
 
//Power on Setting 
LCD_WR_REG(0x18,0x1E);     //Frame rate 72Hz 
LCD_WR_REG(0x19,0x01);     //OSC_EN='1', start Osc 
LCD_WR_REG(0x01,0x00);     //DP_STB='0', out deep sleep 
LCD_WR_REG(0x1F,0x88);    //STB=0 
Delayms(5); 
LCD_WR_REG(0x1F,0x80);      //DK=0 
Delayms(5); 
LCD_WR_REG(0x1F,0x90);    //PON=1 
Delayms(5); 
LCD_WR_REG(0x1F,0xD0);    //VCOMG=1 
Delayms(5); 
 LCD_WR_REG(0x2F,0x00);
//262k/65k color selection 
LCD_WR_REG(0x17,0x05);     //default 0x06 262k color // 0x05 65k color 
 
//SET PANEL 
LCD_WR_REG(0x16,0xA0);
LCD_WR_REG(0x36,0x09);     //REV_P, SM_P, GS_P, BGR_P, SS_P 
LCD_WR_REG(0x29,0x31);     //400 lines 
LCD_WR_REG(0x71,0x1A);     //RTN 

//Gamma 2.2 Setting     
 LCD_WR_REG(0x40,0x01); 
 LCD_WR_REG(0x41,0x08); 
 LCD_WR_REG(0x42,0x04); 
 LCD_WR_REG(0x43,0x2D); 
 LCD_WR_REG(0x44,0x30); 
 LCD_WR_REG(0x45,0x3E); 
 LCD_WR_REG(0x46,0x02); 
 LCD_WR_REG(0x47,0x69); 
 LCD_WR_REG(0x48,0x07); 
 LCD_WR_REG(0x49,0x0E); 
 LCD_WR_REG(0x4A,0x12); 
 LCD_WR_REG(0x4B,0x14); 
 LCD_WR_REG(0x4C,0x17); 
 
 LCD_WR_REG(0x50,0x01); 
 LCD_WR_REG(0x51,0x0F); 
 LCD_WR_REG(0x52,0x12); 
 LCD_WR_REG(0x53,0x3B); 
 LCD_WR_REG(0x54,0x37); 
 LCD_WR_REG(0x55,0x3E); 
 LCD_WR_REG(0x56,0x16); 
 LCD_WR_REG(0x57,0x7D); 
 LCD_WR_REG(0x58,0x08); 
 LCD_WR_REG(0x59,0x0B); 
 LCD_WR_REG(0x5A,0x0D); 
 LCD_WR_REG(0x5B,0x11); 
 LCD_WR_REG(0x5C,0x18); 
 LCD_WR_REG(0x5D,0xFF); 
 
LCD_WR_REG(0x1B,0x001a); //VRH 
LCD_WR_REG(0x25,0x0055); //NVRH 
LCD_WR_REG(0x1A,0x0010); //BT 
LCD_WR_REG(0x1E,0x0038); //FS1   

//Display ON Setting 
LCD_WR_REG(0x28,0x38);      //GON=1, DTE=1, D=10 
Delayms(40); 
LCD_WR_REG(0x28,0x3C);      //GON=1, DTE=1, D=11 
 
WriteComm(0x22);               //Start GRAM write 
}




/*************************************************
函数名:Lcd光标起点定位函数
功能:指定320240液晶上的一点作为写数据的起始点
入口参数:x 坐标 0~239
          y 坐标 0~319
返回值:无
*************************************************/
void Lcd_SetCursor(u16 x,u16 y)
{ 
  LCD_WriteRegIndex(0x20);
  LCD_WriteData(x);//水平坐标
  LCD_WriteRegIndex(0x21);
  LCD_WriteData(y);//垂直坐标 
} 
void SPILCD_SetWindow(unsigned short xstat,unsigned short xend,unsigned short ystat,unsigned short yend)
{
	//Set GRAM Area 
	LCD_WR_REG(0x02,xstat>>8); 
	LCD_WR_REG(0x03,xstat&0xff);     //Column Start 
	LCD_WR_REG(0x04,xend>>8); 
	LCD_WR_REG(0x05,xend&0xff);     //Column End 
	 
	LCD_WR_REG(0x06,ystat>>8); 
	LCD_WR_REG(0x07,ystat&0xff);     //Row Start 
	LCD_WR_REG(0x08,yend>>8); 
	LCD_WR_REG(0x09,yend&0xff);     //Row End 

	WriteComm(0x22);
}
void SPILCD_Fill(unsigned short xsta,unsigned short ysta,unsigned short xend,unsigned short yend,unsigned short color)
{                    
	unsigned short i,j;
	//设置窗口		
	SPILCD_SetWindow(xsta,xend-1,ysta,yend-1);
	for(i=xsta;i<=xend;i++)
		for(j=ysta;j<=yend;j++)
	{
		   	LCD_WriteData(color);	  //显示所填充的颜色. 
	}    
}
/******************************************
函数名:Lcd图像填充100*100
功能:向Lcd指定位置填充图像
入口参数:
******************************************/
void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, const unsigned char* pic)
{
  unsigned long i,j;
	j=pic_H*pic_V*2;
	SPILCD_SetWindow(x,x+pic_H-1,y,y+pic_V-1);
	for (i = 0; i < j; i++)
	{
    LCD_WriteByteSPI(pic[i]);
	}
}
//=============== 在x,y 坐标上打一个颜色为Color的点 ===============
void DrawPixel(u16 x, u16 y, int Color)
{
	SPILCD_SetWindow(x,x,y,y); 
  LCD_WriteData(Color);							  
}
//------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------
//8*16字体 ASCII码 显示
//函数名:SPILCD_ShowChar
//参  数:
//(x,y): 
//num:要显示的字符:" "--->"~"
//flag:有背景色(1)无背景色(0)
void SPILCD_ShowChar(unsigned short x,unsigned short y,unsigned char num, unsigned int fColor, unsigned int bColor,unsigned char flag) 
{       
	unsigned char temp;
	unsigned int pos,i,j;  

	num=num-' ';//得到偏移后的值
	i=num*16; 	
	for(pos=0;pos<16;pos++)
		{
			temp=nAsciiDot[i+pos];	//调通调用ASCII字体
			for(j=0;j<8;j++)
		   {                 
		        if(temp&0x80)
							DrawPixel(x+j,y,fColor);
						else 
							if(flag) DrawPixel(x+j,y,bColor); //如果背景色标志flag为1
							temp<<=1; 
		    }
			 y++;
		}		 
}  

//写一个16x16的汉字
void PutGB1616(unsigned short x, unsigned short  y, unsigned char c[2], unsigned int fColor,unsigned int bColor,unsigned char flag)
{
	unsigned int i,j,k;
	unsigned short m;
	for (k=0;k<64;k++) { //64标示自建汉字库中的个数,循环查询内码
	  if ((codeGB_16[k].Index[0]==c[0])&&(codeGB_16[k].Index[1]==c[1]))
			{ 
    	for(i=0;i<32;i++) 
			{
				m=codeGB_16[k].Msk[i];
				for(j=0;j<8;j++) 
				{		
					if((m&0x80)==0x80) {
						DrawPixel(x+j,y,fColor);
						}
					else {
						if(flag) DrawPixel(x+j,y,bColor);
						}
					m=m<<1;
				} 
				if(i%2){y++;x=x-8;}
				else x=x+8;
		  }
		}  
	  }	
	}

//显示一串字
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag) 
{
	unsigned char l=0;
	while(*s) 
		{
			if( *s < (char)0x80) 
					{
						SPILCD_ShowChar(x+l*8,y,*s,fColor,bColor,flag);
						s++;l++;
					}
			else
					{
						PutGB1616(x+l*8,y,(unsigned char*)s,fColor,bColor,flag);
						s+=2;l+=2;
					}
		}
}

相关文章:

  • 【云原生 · Kubernetes】Taint和Toleration(污点和容忍)
  • 10.20复习
  • 自动化测试项目实战笔记(三):测试用户注册(验证码错误,成功,出现弹框时处理)
  • Pygame实战(一):随机抽位置
  • vue支付项目-APP微信支付功能
  • 新手如何自学python?
  • Java的日期与时间之java.time.ZonedDateTime简介说明
  • Vue整合Markdown组件+SpringBoot文件上传+代码差异对比
  • MySQL高级篇——索引简介
  • C-内存函数(大量图解,函数实现)
  • 【STM32】MDK下的C语言基础
  • web前端面试题附答案041 - 曾经一个百度面试官问我,localStorage可以存对象吗?
  • 【Linux学习】权限
  • 基于AT89C51单片机的直流数字电压表设计
  • 脚本控制向Android模拟拨打电话,发送短信,定位设置功能
  • “大数据应用场景”之隔壁老王(连载四)
  • 《深入 React 技术栈》
  • 30天自制操作系统-2
  • Angular6错误 Service: No provider for Renderer2
  • bootstrap创建登录注册页面
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • DataBase in Android
  • HTTP 简介
  • Intervention/image 图片处理扩展包的安装和使用
  • Java 23种设计模式 之单例模式 7种实现方式
  • Javascript编码规范
  • JavaScript学习总结——原型
  • Java面向对象及其三大特征
  • Redux 中间件分析
  • SpiderData 2019年2月16日 DApp数据排行榜
  • spring security oauth2 password授权模式
  • 关于for循环的简单归纳
  • 试着探索高并发下的系统架构面貌
  • 详解移动APP与web APP的区别
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 数据可视化之下发图实践
  • ​学习一下,什么是预包装食品?​
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #define 用法
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • .NET DataGridView数据绑定说明
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .net和php怎么连接,php和apache之间如何连接
  • @AliasFor注解
  • @ModelAttribute注解使用
  • [BUG]vscode插件live server无法自动打开浏览器
  • [CISCN2019 华东南赛区]Web4