五、STM32移植u8g2图形库(Pulse sensor和AHT10调试)

(硬件SPI代码已测试,硬件I2C代码未测试)

一、源码下载

U8g2 是一个用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,并支持如SSD1306等多种类型的OLED驱动。

 U8g2源码的开源库地址:https://github.com/olikraus/u8g2

二、移植修改 

U8g2 的官方移植教程 https://github.com/olikraus/u8g2/wiki/Porting-to-new-MCU-platform

1. 只保留csrc文件夹内容

2.u8x8_d_器件名.c

csrc下的文件,其中u8x8_d_器件名.c的文件只需保留自己对应的显示器驱动芯片即可,比如OLED12864显示器,显示器驱动为SSD1306,分辨率为128x64,选择的文件为u8x8_d_ssd1306_128x64_noname.c

3. 修改u8g2_d_setup.c文件

只保留自己使用的芯片对应的setup文件。u8g2_Setup_ssd1306_128x64_noname_f

4.修改u8g2_d_memory.c

它需要根据 u8g2_d_setup.c 中的调用情况决定用到哪些函数。由于 u8g2_Setup_ssd1306_i2c_128x64_noname_f() 函数只用到 u8g2_m_16_8_f() 这一个函数,因此只需要保留它,其余函数全部删除即可

4.精简字体文件

 u8x8_fonts.c 和 u8g2_fonts.c ,尤其是 u8g2_fonts.c 

字体类型的变量非常多,建议先复制一个备份后将所有变量删除,之后视情况再添加字体。字体变量的命名大致遵循以下规则:

5. 回调

创建u8g2_init.h

#ifndef __U8G2_INIT_H__
#define __U8G2_INIT_H__

#include "main.h"
#include "u8g2.h"

void u8g2Init(u8g2_t *u8g2);
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,void *arg_ptr);

/*Hw I2C*/
//uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
#endif

创建u8g2_init.c

#include "u8g2.h"
#include "u8g2_init.h"
#include "main.h"
#include "spi.h"
//#include "i2c.h"

/*硬件SPI回调函数*/
uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,void *arg_ptr)
{
    switch (msg)
    {
        case U8X8_MSG_BYTE_SEND: /*通过SPI发送arg_int个字节数据*/
//          HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)arg_ptr, arg_int);while(hspi1.TxXferCount);
			//使用DMA可以将上面的注释解除,把下面不带DMA的给注释掉
			HAL_SPI_Transmit(&hspi1,(uint8_t *)arg_ptr,arg_int,200);
            break;
        case U8X8_MSG_BYTE_INIT: /*初始化函数*/
            break;
        case U8X8_MSG_BYTE_SET_DC: /*设置DC引脚,表明发送的是数据还是命令*/
			HAL_GPIO_WritePin(OLED_DC_GPIO_Port,OLED_DC_Pin,arg_int);
            break;
        case U8X8_MSG_BYTE_START_TRANSFER: 
            u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
            u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
            break;
        case U8X8_MSG_BYTE_END_TRANSFER: 
            u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
            u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
            break;
        default:
            return 0;
    }
    return 1;
}

 uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
     switch (msg)
     {

        case U8X8_MSG_GPIO_AND_DELAY_INIT: /*delay和GPIO的初始化,在main中已经初始化完成了*/
            break;
        case U8X8_MSG_DELAY_MILLI: /*延时函数*/
            HAL_Delay(arg_int);     //调用谁stm32系统延时函数
            break;
        case U8X8_MSG_GPIO_CS: /*片选信号*/ //由于只有一个SPI设备,所以片选信号在初始化时已经设置为为常有效
            HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, arg_int);
            break;
        case U8X8_MSG_GPIO_DC: /*设置DC引脚,表明发送的是数据还是命令*/
            HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, arg_int);
            break;
        case U8X8_MSG_GPIO_RESET:
            break;
     }
     return 1;
 }

void u8g2Init(u8g2_t *u8g2)
{
	HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_SET); //显示器复位拉高   
	u8g2_Setup_ssd1306_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_4wire_hw_spi, u8x8_gpio_and_delay);  // 初始化0.96寸OLED u8g2 结构体
	u8g2_InitDisplay(u8g2);     //初始化显示
	u8g2_SetPowerSave(u8g2, 0); //开启显示
}


///*硬件I2C HAL (未测试)*/
// uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
//{
//	switch(msg){
//		
//	case U8X8_MSG_GPIO_AND_DELAY_INIT:
//	    break;
//		
//	case U8X8_MSG_DELAY_MILLI:
//		HAL_Delay(arg_int);//change it!
//	    break;
//		
//	default:	
//		return 0;
//	}
//	return 1; // command processed successfully.
//}


//uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
//{
//  static uint8_t buffer[32];		/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
//  static uint8_t buf_idx;
//  uint8_t *data;
// 
//  switch(msg)
//  {
//    case U8X8_MSG_BYTE_SEND:
//      data = (uint8_t *)arg_ptr;      
//      while( arg_int > 0 )
//      {
//	        buffer[buf_idx++] = *data;
//	        data++;
//	        arg_int--;
//      }      
//      break;
//    case U8X8_MSG_BYTE_INIT:
//      /* add your custom code to init i2c subsystem */
//      break;
//    case U8X8_MSG_BYTE_SET_DC:
//      /* ignored for i2c */
//      break;
//    case U8X8_MSG_BYTE_START_TRANSFER:
//      buf_idx = 0;
//      break;
//    case U8X8_MSG_BYTE_END_TRANSFER:
//      HAL_I2C_Master_Transmit(&hi2c1,u8x8_GetI2CAddress(u8x8), buffer, buf_idx,0x100);//change it
//      break;
//    default:
//      return 0;
//  }
//  return 1;
//}

//void u8g2Init(u8g2_t *u8g2)
//{
//	HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_SET); //显示器复位拉高   
//	u8g2_Setup_ssd1306_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay);  // 初始化0.96寸OLED u8g2 结构体
//	u8g2_InitDisplay(u8g2);     //初始化显示
//	u8g2_SetPowerSave(u8g2, 0); //开启显示
//}

三、调试

1.mybmp.c & mybmp.h

Img2Lcd软件转换图片为bmp格式

 生成字模

mybmp.c

#include "mybmp.h"

const uint8_t Cuteghost_BMP[] = {
 /*字模

*/
    /* 32*32 */
};


const uint8_t Lighting_BMP[] = {
 /*字模

*/
    /* 32*32 */
};


//...........自行添加

mybmp.h

#ifndef __MYBMP_H
#define __MYBMP_H

extern const uint8_t Lighting_BMP[];
extern const uint8_t Cuteghost_BMP[];

//.........

#endif

2.main.c添加或修改

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "u8g2_init.h"
#include "AHT10.h"
#include "appheart.h"
#include "mybmp.h"

extern uint16_t usPulse[128];  //心率采集缓存数组
extern uint8_t  ucPos;         //心率数据保存位置
u8g2_t u8g2;
/* USER CODE END Includes */       //添加

int main(void)
{
  ahtData_t AhtData;
  uint8_t i;
  uint8_t ucPulse = 0;    
  uint16_t usMaxValue = 0; 
	

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_I2C2_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
  u8g2Init(&u8g2);
  u8g2_ClearBuffer(&u8g2);

  while (1)
  {
		HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
/*AHT10*/
        char temDataTime[10];
		char humDataTime[10];
		AHT10_Read_predata(&AhtData);
		sprintf(temDataTime, "TEM: %.1f C", AhtData.temp);
		sprintf(humDataTime, "HUM: %d% %", (uint8_t)AhtData.humi);	
		u8g2_SendBuffer(&u8g2);
//		u8g2_SetFont(&u8g2, u8g2_font_DigitalDiscoThin_tf);		
		u8g2_SetFont(&u8g2, u8g2_font_ncenB12_tf);
//		u8g2_SetFont(&u8g2, u8g2_font_inb24_mf);   //选择字库,选谁,打开谁
		u8g2_DrawStr(&u8g2, 3,20,temDataTime);
		u8g2_DrawStr(&u8g2, 3,40,humDataTime);
/*Pulse Sensor*/	
		char heartDataTime[10];		
		HAL_ADC_Start(&hadc1);
    getPulse(&ucPulse, &usMaxValue);
		if(ucPos == 0)
		{
			for(i=0;i<128;i++)
			{
			}
			sprintf(heartDataTime, "BPM:  %d", ucPulse);
		  u8g2_DrawStr(&u8g2, 3,60,heartDataTime);
			printf("心率%d/分钟   \n",ucPulse);
		}

		printf("温度:%d/n",(uint8_t)AhtData.humi);
		printf("湿度:%d/n",(uint8_t)AhtData.temp);	
		HAL_Delay(20);

/*图像*/
//        u8g2_SendBuffer(&u8g2);
//        u8g2_DrawBox(&u8g2, 19, 25, 20, 20);
//        u8g2_DrawFrame(&u8g2, 10, 45, 19, 19);
//		  u8g2_SetFont(&u8g2, u8g2_font_DigitalDiscoThin_tf);
//        u8g2_DrawStr(&u8g2, 0, 18, "Cold-blooded");
//	    	u8g2_SetFont(&u8g2, u8g2_font_inb24_mf);
//		 u8g2_DrawStr(&u8g2, 100, 25, "M");
				
//		u8g2_DrawXBMP(&u8g2, 50, 30, 32, 32, Lighting_BMP);
//		u8g2_DrawXBMP(&u8g2, 90, 30, 32, 32, Cuteghost_BMP);   				
//        HAL_Delay(200);	
  }
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是一款广泛应用于嵌入式系统开发的微控制器系列,而PulseSensor是一种用于心率检测的传感器。在STM32上使用PulseSensor需要进行相应的代码编写和配置。 以下是一个简单的示例代码,用于在STM32上使用PulseSensor进行心率检测: ```c #include "stm32f4xx.h" #define PULSE_SENSOR_PIN GPIO_Pin_0 #define PULSE_SENSOR_PORT GPIOA void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = PULSE_SENSOR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(PULSE_SENSOR_PORT, &GPIO_InitStructure); } void TIM_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 设置定时器周期为1ms TIM_TimeBaseStructure.TIM_Prescaler = 8400 - 1; // 设置定时器预分频为8400,得到10kHz的计数频率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM2, ENABLE); } void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { // 在这里进行心率检测的处理逻辑 // 可以通过读取PULSE_SENSOR_PIN的电平状态来获取心率信号 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } int main(void) { GPIO_Configuration(); TIM_Configuration(); while (1) { // 在这里可以进行其他的任务处理 } } ``` 以上代码中,首先需要进行GPIO和定时器的配置。GPIO配置函数`GPIO_Configuration()`用于配置PulseSensor的引脚,这里假设使用的是PA0引脚。定时器配置函数`TIM_Configuration()`用于配置定时器,这里使用的是TIM2定时器,并设置了1ms的定时周期。 在定时器中断处理函数`TIM2_IRQHandler()`中,可以编写心率检测的处理逻辑。通过读取PULSE_SENSOR_PIN引脚的电平状态,可以获取到心率信号。 在主函数中,可以添加其他任务处理逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值