ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

RFID防伪设计(物联网工程课程设计)DAY4---LCD屏幕显示

2021-05-09 20:57:46  阅读:173  来源: 互联网

标签:课程设计 WriteCmd DAY4 RFID unsigned char OLED I2C void


重点来了

这个课程设计中硬件方面一共会有两个重点
其中一个自然就是今天要做的OLCD屏幕的驱动
第二个是RFID标签的读写

由于我买的是野火的I2C OLCD屏幕,自然选择野火自带的例程进行修改,让其能够适配HAL库的开发

当然既然是I2C的OLCD,那必然离不开I2C协议
值得一提的是,在stm32要实现I2C,可以选择两种方式
1.硬件I2C
2.软件模拟I2C

虽然火哥在标准库的视频中说过硬件I2C可能会存在一定的问题,但是既然买了板子,当然要用哇,不用岂不是暴殄天物。
所以,我们还是在cubemx中对硬件进行配置,然后驱动OLCD屏幕

I2C是一种协议,当然其核心还是时序逻辑,软件I2C同样好用,但是对编程稍微较高,未来可能会在b站上录制相应的视频

stm32cubemx

首先还是查找硬件相关的手册
这里就不在截图了
总之,选择PB6、PB7引脚输出I2C,正好对应为I2C1的配置

在cubemx中进行配置
在这里插入图片描述
I2C的模式当然就是选择I2C
subus可以自己看看,按照火哥讲的,这个是另一种协议不在考虑范围内
下面就是I2C的详细配置
选择高速模式,这个是由外设决定
OLCD支持高速模式,所以可以这样设置
占空比选择2
延迟Disabled
地址位数7
Disabled
slave地址0(不选用主从模式)

然后生成代码

keil5

好!
工程变得越来越复杂了,我们细心的构建一下工程目录
除了系统自动生成的文件夹外,我们在自己创建一个
user
文件夹,用于存放自己编写的文件
工程目录如下:
在这里插入图片描述
其中**.ioc**文件当然就是cubemx文件(存放路径不要有中文名,要全英文)
core就是包含src和inc,即c文件和头文件的地方属于系统配置文件,包括着各种系统外设的初始化
Drivers芯片包文件
MDK-ARM工程文件以及各种Debug生成文件
User文件夹就是自己创建的文件

点进user文件夹中
在这里插入图片描述
oled就是所有有关oled的模块文件(OLCD)
bsp_system.h文件中包含着全部的自己创建的头文件
(未来大型工程,每次都要写一遍包含头文件太麻烦了)
codetable.h字模表,可以不用管,这是为了LCD中显示中文而用的,如果不用显示中文可以将这个头文件删除

买外设的时候必然会给你提供一定的例程文件
我这里就不再进行分析了,比较麻烦,有兴趣的自己看就行了
总之你需要在keil中有这几个文件
在这里插入图片描述
自己添加的就是这个OLED_I2C.c文件以及相关的头文件
在这个文件里面有所有有关OLED的函数
下面是OLED_I2C.c文件

#include "OLED_I2C.h"
#include "i2c.h"
#include "codetab.h"
#include "stm32f1xx_hal.h"
void WriteCmd(unsigned char I2C_OLED_COMmand)//写命令
{
	HAL_I2C_Mem_Write(&hi2c1,OLED_ADD,OLED_COM,I2C_MEMADD_SIZE_8BIT,&I2C_OLED_COMmand,1,100);
}
		
void WriteOLED_DAT(unsigned char I2C_OLED_DATa)//写数据
{
	HAL_I2C_Mem_Write(&hi2c1,OLED_ADD,OLED_DAT,I2C_MEMADD_SIZE_8BIT,&I2C_OLED_DATa,1,100);	
}
 
	void OLED_Init(void)
{
	HAL_Delay(100); //这里的延时很重要
	
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set OLED_COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度调节 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set OLED_COM pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vOLED_COMh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
}

void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{ 
	WriteCmd(0xb0+y);
	WriteCmd(((x&0xf0)>>4)|0x10);
	WriteCmd((x&0x0f)|0x01);
}

void OLED_Fill(unsigned char fill_OLED_DATa)//全屏填充
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<128;n++)
			{
				WriteOLED_DAT(fill_OLED_DATa);
			}
	}
}


void OLED_CLS(void)//清屏
{
	OLED_Fill(0x00);
}

void OLED_ON(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X14);  //开启电荷泵
	WriteCmd(0XAF);  //OLED唤醒
}

void OLED_OFF(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X10);  //关闭电荷泵
	WriteCmd(0XAE);  //OLED休眠
}


// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16)
// Description    : 显示codetab.h中的ASCII字符,有6*8和8*16可选择
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
	unsigned char c = 0,i = 0,j = 0;
	switch(TextSize)
	{
		case 1:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 126)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteOLED_DAT(F6x8[c][i]);
				x += 6;
				j++;
			}
		}break;
		case 2:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 120)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<8;i++)
					WriteOLED_DAT(F8X16[c*16+i]);
				OLED_SetPos(x,y+1);
				for(i=0;i<8;i++)
					WriteOLED_DAT(F8X16[c*16+i+8]);
				x += 8;
				j++;
			}
		}break;
	}
}


// Parameters     : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在.h中的索引
// Description    : 显示ASCII_8x16.h中的汉字,16*16点阵
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteOLED_DAT(F16x16[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteOLED_DAT(F16x16[adder]);
		adder += 1;
	}
}



// Parameters     : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
// Description    : 显示BMP位图
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteOLED_DAT(BMP[j++]);
		}
	}
}






void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值			
		if(x>128-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			OLED_SetPos(x,y);	
			for(i=0;i<8;i++)
			WriteOLED_DAT(F8X16[c*16+i]);
			OLED_SetPos(x,y+1);
			for(i=0;i<8;i++)
			WriteOLED_DAT(F8X16[c*16+i+8]);
			}
			else {	
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
				WriteOLED_DAT(F6x8[c][i]);
				
			}
}
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}	


//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 

后面会有分析

OLED_I2C.h头文件

#ifndef __OLED_I2C_H
#define	__OLED_I2C_H

#include "i2c.h"
 
#define u8 uint8_t
#define u32 uint32_t

#define OLED_ADD	0x78  // OLED的I2C地址(禁止修改)
#define OLED_COM				0x00  // OLED 指令(禁止修改)
#define OLED_DAT 			0x40  // OLED 数据(禁止修改)

void WriteCmd(unsigned char I2C_Command);//写命令
void WriteDat(unsigned char I2C_Data);//写数据
void OLED_Init(void);//初始化
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_Fill(unsigned char fill_Data);//全屏填充
void OLED_CLS(void);
void OLED_ON(void);
void OLED_OFF(void);
void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize);//显示字符串
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N);//显示汉字
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]);//显示图片

void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2);//size2(16|12)

#endif

头文件主要是对c文件中定义的函数进行声明
同时定义一些变量
注意
#ifndef #define #endif
防止头文件被重复定义

bsp_system.h

#ifndef __BSP_SYSTEM_H
#define __BSP_SYSTEM_H

#include "stdio.h"
#include "OLED_I2C.h"

#endif /* __BSP_SYSTEM_H */

最后是main.c文件

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_system.h"


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

uint8_t send_date[64] = {0};

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	OLED_Init();
  OLED_CLS();
	

  OLED_ShowStr(0,0,(unsigned char*)"Hello world",2);
 	OLED_ON(); 
	
	
  while (1)
  {
		
		//串口调试
		sprintf((char *)send_date,"test date\n");
		HAL_UART_Transmit(&huart1, send_date, sizeof(send_date), 100);
		//HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
		HAL_Delay(500);
		
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

好,代码都上传完了,那么接下来就是代码解释
main文件和那些头文件没啥可说的
主要是程序移植过程中的OLED_I2C.c文件中的内容
看起来函数很多实际上就一两个函数需要修改
最底层的函数只有2个

void WriteCmd(unsigned char I2C_OLED_COMmand)//写命令
{
	HAL_I2C_Mem_Write(&hi2c1,OLED_ADD,OLED_COM,I2C_MEMADD_SIZE_8BIT,&I2C_OLED_COMmand,1,100);
}
		
void WriteOLED_DAT(unsigned char I2C_OLED_DATa)//写数据
{
	HAL_I2C_Mem_Write(&hi2c1,OLED_ADD,OLED_DAT,I2C_MEMADD_SIZE_8BIT,&I2C_OLED_DATa,1,100);	
}

一个函数是写指令一个是写数据
驱动OLCD实际上还是对寄存器进行读写,特定的寄存器有特定的地址
所以我们在头文件中定义的了相对应的地址

#define OLED_ADD	0x78  // OLED的I2C地址(禁止修改)
#define OLED_COM				0x00  // OLED 指令(禁止修改)
#define OLED_DAT 			0x40  // OLED 数据(禁止修改)

根据地址写入数据对屏幕进行驱动

HAL库相关函数为

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);

阻塞模式直接对Mem进行读写

为什么野火例程会有那么长,你这里就这么点?
野火程序,是为了程序的健壮性,
例程例程,当然是给你最好的东西,防止出错,同时对时序进行一定判断
其实有部分程序已经在hal的函数中进行了集成,不需要自己考虑
很方便

效果

在这里插入图片描述

标签:课程设计,WriteCmd,DAY4,RFID,unsigned,char,OLED,I2C,void
来源: https://blog.csdn.net/weixin_44726459/article/details/116569419

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有