打印
[开发板]

【CW32L031CxTx StartKit评估板测评】OLED显示人体检测

[复制链接]
215|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#上期咱分享了关于驱动HC-SR501红外人体检测模块的内容,上期贴子:https://bbs.21ic.com/icview-3337106-1-1.html
     今天使用OLED屏幕实时监测HC-SR501检测结果,如若红外监测模块检测到有人经过,则OLED屏展现“有人经过”,OLED模块采用IIC通讯方式。
     此次实现监测功能,用到的硬件接口有:
     HC-SR501-OUT:GPIOA_7
     OLED-SCL:       GPIOB_10
     OLED-SDA:       GPIOB_11
     硬件连接示意图如下:

     由于官方提供的底层库函数与标准的STM32库函数很相似,因此移植基于STM32的工程就变得非常简单啦。工程中运用到提取字模的软件,众所周知,“PCtoLCD2002”非常好用,菜单中“模式”有“字符模式”与“图形模式”,根据需求我们可以使用该取模软件对中文字符进行取模,或者对单色位图进行取模。取模软件的选项设置如下:

      部分代码展示如下:
/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp_HC-SR501.h"

/**
  * 函数功能: 人体红外感应模块IO引脚初始化.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:对人体红外感应模块接入的引脚进行初始化
  *           
  */
void HC_SR501_GPIO_Init(void)
{
   /* 定义IO硬件初始化结构体变量 */
  GPIO_InitTypeDef GPIO_InitStruct;
       
        /* 使能(开启)HC_SR501引脚对应IO端口时钟 */  
        __RCC_GPIOA_CLK_ENABLE();
   
        //GPIO_InitStruct.IT = GPIO_IT_HIGH;
        /* 设定HC_SR501对应引脚IO为浮空输入模式 */
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;  
  /* 设定HC_SR501对应引脚IO编号 */
  GPIO_InitStruct.Pins = HC_SR501_GPIO_PIN;  

  /* 初始化HC_SR501对应引脚IO */
  GPIO_Init(HC_SR501_GPIO, &GPIO_InitStruct);
}

/**
  * 函数功能: 简单粗暴的延时函数
  * 输入参数: time;延时时间设置
  * 返 回 值: 无
  * 说    明:软件消抖
  */
static void HC_SR501_ScanDelay(void)
{  
  uint32_t i,j;
  for(i=0;i<10;++i)
    for(j=0;j<100;++j){ }               
}

/**
  * 函数功能: 读取引脚的状态
  * 输入参数:无
  * 返 回 值: HC_SR501_HIGH:有人;
  *           HC_SR501_LOW:没人
  * 说    明:无。
  */
HC_SR501_State_TypeDef HC_SR501_StateRead(void)
{
  /* 读取模块输出信号,若此时输出的是高电平 ,则进入下一步判断*/
  if(GPIO_ReadPin(HC_SR501_GPIO,HC_SR501_GPIO_PIN)==HC_SR501_ACTIVE_LEVEL)
  {
    /* 延时一小段时间,消除抖动 */
    HC_SR501_ScanDelay();
    /* 延时时间后再来判断引脚状态,如果还是高电平那么确实就是高电平 */
    if(GPIO_ReadPin(HC_SR501_GPIO,HC_SR501_GPIO_PIN)==HC_SR501_ACTIVE_LEVEL)
    {      
       /* 按键扫描完毕,确定有人,返回有人状态(高电平) */
      return HC_SR501_HIGH;
    }
  }
  /* 没人,返回没人状态 */
  return HC_SR501_LOW;
}
#ifndef __BSP_HC_SR501_H__
#define __BSP_HC_SR501_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "../inc/main.h"

/* 类型定义 --------------------------------------------------------------*/
typedef enum
{
  HC_SR501_LOW   = 0,
  HC_SR501_HIGH = 1,
}HC_SR501_State_TypeDef;

/* 宏定义 --------------------------------------------------------------------*/
#define HC_SR501_RCC_CLK_ENABLE()         _RCC_GPIOA_CLK_ENABLE()
#define HC_SR501_GPIO_PIN                 GPIO_PIN_7
#define HC_SR501_GPIO                     CW_GPIOA
#define HC_SR501_ACTIVE_LEVEL             1

/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void HC_SR501_GPIO_Init(void);
HC_SR501_State_TypeDef HC_SR501_StateRead(void);

#endif  
#include "stdlib.h"
#include "oled.h"
#include "oledfont.h"
#include "../inc/main.h"

void IIC_Start()
{
        OLED_SCLK_Set();
        OLED_SDIN_Set();
        OLED_SDIN_Clr();
        OLED_SCLK_Clr();
}

//IIC Stop
void IIC_Stop()
{
        OLED_SCLK_Set() ;
        //OLED_SCLK_Clr();
        OLED_SDIN_Clr();
        OLED_SDIN_Set();
       
}

void IIC_Wait_Ack()
{
        OLED_SCLK_Set() ;
        OLED_SCLK_Clr();
}

// IIC Write byte

void Write_IIC_Byte(unsigned char IIC_Byte)
{
        unsigned char i;
        unsigned char m,da;
        da=IIC_Byte;
        OLED_SCLK_Clr();
        for(i=0;i<8;i++)               
        {
                m=da;
                m=m&0x80;
                if(m==0x80)
                {OLED_SDIN_Set();}
                else OLED_SDIN_Clr();
                        da=da<<1;
                OLED_SCLK_Set();
                OLED_SCLK_Clr();
                }


}

// IIC Write Command

void Write_IIC_Command(unsigned char IIC_Command)
{
   IIC_Start();
   Write_IIC_Byte(0x78);            //Slave address,SA0=0
        IIC_Wait_Ack();       
   Write_IIC_Byte(0x00);                        //write command
        IIC_Wait_Ack();       
   Write_IIC_Byte(IIC_Command);
        IIC_Wait_Ack();       
   IIC_Stop();
}

// IIC Write Data

void Write_IIC_Data(unsigned char IIC_Data)
{
   IIC_Start();
   Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0
        IIC_Wait_Ack();       
   Write_IIC_Byte(0x40);                        //write data
        IIC_Wait_Ack();       
   Write_IIC_Byte(IIC_Data);
        IIC_Wait_Ack();       
   IIC_Stop();
}
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
        if(cmd)
                        {

   Write_IIC_Data(dat);
   
                }
        else {
   Write_IIC_Command(dat);
               
        }
}


// fill_Picture

void fill_picture(unsigned char fill_Data)
{
        unsigned char m,n;
        for(m=0;m<8;m++)
        {
                OLED_WR_Byte(0xb0+m,0);                //page0-page1
                OLED_WR_Byte(0x00,0);                //low column start address
                OLED_WR_Byte(0x10,0);                //high column start address
                for(n=0;n<128;n++)
                        {
                                OLED_WR_Byte(fill_Data,1);
                        }
        }
}


/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
        unsigned int m;
        for(;Del_50ms>0;Del_50ms--)
                for(m=6245;m>0;m--);
}

//坐标设置

        void OLED_Set_Pos(unsigned char x, unsigned char y)
{         OLED_WR_Byte(0xb0+y,OLED_CMD);
        OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
        OLED_WR_Byte((x&0x0f),OLED_CMD);
}             
//开启OLED显示   
void OLED_Display_On(void)
{
        OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
        OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
        OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
        OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
        OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
        OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}                                            
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!          
void OLED_Clear(void)  
{  
        u8 i,n;                    
        for(i=0;i<8;i++)  
        {  
                OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
                OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
                OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
                for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
        } //更新显示
}
void OLED_On(void)  
{  
        u8 i,n;                    
        for(i=0;i<8;i++)  
        {  
                OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
                OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
                OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
                for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
        } //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示                                 
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{             
        unsigned char c=0,i=0;       
                c=chr-' ';//得到偏移后的值                       
                if(x>Max_Column-1){x=0;y=y+2;}
                if(Char_Size ==16)
                        {
                        OLED_Set_Pos(x,y);       
                        for(i=0;i<8;i++)
                        OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
                        OLED_Set_Pos(x,y+1);
                        for(i=0;i<8;i++)
                        OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
                        }
                        else {       
                                OLED_Set_Pos(x,y);
                                for(i=0;i<6;i++)
                                OLED_WR_Byte(F6x8[c][i],OLED_DATA);
                               
                        }
}
//m^n函数
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);
        }
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
        unsigned char j=0;
        while (chr[j]!='\0')
        {                OLED_ShowChar(x,y,chr[j],Char_Size);
                        x+=8;
                if(x>120){x=0;y+=2;}
                        j++;
        }
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{                                  
        u8 t,adder=0;
        OLED_Set_Pos(x,y);       
    for(t=0;t<16;t++)
                {
                                OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
                                adder+=1;
     }       
                OLED_Set_Pos(x,y+1);       
    for(t=0;t<16;t++)
                        {       
                                OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
                                adder+=1;
      }                                       
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
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_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
            {      
                    OLED_WR_Byte(BMP[j++],OLED_DATA);                   
            }
        }
}

//初始化SSD1306                                            
void OLED_Init(void)
{        
          GPIO_InitTypeDef  configStruct;
                /* enable the OLED GPIO clock */
                __RCC_GPIOB_CLK_ENABLE();

    /* configure OLED GPIO pin */
                configStruct.Pins = GPIO_PIN_10|GPIO_PIN_11;
          configStruct.Mode = GPIO_MODE_OUTPUT_PP;
    configStruct.IT = GPIO_IT_NONE;
          GPIO_Init(CW_GPIOB, &configStruct);
       
          GPIO_WritePin(CW_GPIOB,GPIO_PIN_10,GPIO_Pin_SET);       
                GPIO_WritePin(CW_GPIOB,GPIO_PIN_11,GPIO_Pin_SET);       
       
    Delay(8000);
    OLED_WR_Byte(0xAE,OLED_CMD);//--display off
                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  
                OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
                OLED_WR_Byte(0x81,OLED_CMD); // contract control
                OLED_WR_Byte(0xFF,OLED_CMD);//--128   
                OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
                OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
                OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
                OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
                OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
                OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
                OLED_WR_Byte(0x00,OLED_CMD);//
               
                OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
                OLED_WR_Byte(0x80,OLED_CMD);//
               
                OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
                OLED_WR_Byte(0x05,OLED_CMD);//
               
                OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
                OLED_WR_Byte(0xF1,OLED_CMD);//
               
                OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
                OLED_WR_Byte(0x12,OLED_CMD);//
               
                OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
                OLED_WR_Byte(0x30,OLED_CMD);//
               
                OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
                OLED_WR_Byte(0x14,OLED_CMD);//
               
                OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}  
#ifndef __OLED_H
#define __OLED_H

#include "cw32l031_gpio.h"
#include "stdlib.h"          
#include "stdint.h"


#define OLED_MODE 0
#define SIZE 8
#define XLevelL                0x00
#define XLevelH                0x10
#define Max_Column        128
#define Max_Row                64
#define        Brightness        0xFF
#define X_WIDTH         128
#define Y_WIDTH         64                                                              
//-----------------OLED IIC端口定义----------------                                            

#define OLED_SCLK_Clr() GPIO_WritePin(CW_GPIOB,GPIO_PIN_10,GPIO_Pin_RESET)//SCL   PB10
#define OLED_SCLK_Set() GPIO_WritePin(CW_GPIOB,GPIO_PIN_10,GPIO_Pin_SET)

#define OLED_SDIN_Clr() GPIO_WritePin(CW_GPIOB,GPIO_PIN_11,GPIO_Pin_RESET)//SDA  PB11
#define OLED_SDIN_Set() GPIO_WritePin(CW_GPIOB,GPIO_PIN_11,GPIO_Pin_SET)

                     
#define OLED_CMD  0        //写命令
#define OLED_DATA 1        //写数据


typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

//OLED控制用函数
void OLED_WR_Byte(unsigned dat,unsigned cmd);  
void OLED_Display_On(void);
void OLED_Display_Off(void);                                                                                          
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size);         
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowCHinese(u8 x,u8 y,u8 no);
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void Delay_50ms(unsigned int Del_50ms);
void Delay_1ms(unsigned int Del_1ms);
void fill_picture(unsigned char fill_Data);
void Picture(void);
void IIC_Start(void);
void IIC_Stop(void);
void Write_IIC_Command(unsigned char IIC_Command);
void Write_IIC_Data(unsigned char IIC_Data);
void Write_IIC_Byte(unsigned char IIC_Byte);
void IIC_Wait_Ack(void);
#endif  
#include "../inc/main.h"
#include "oled.h"
#include "bmp.h"
#include "bsp_HC-SR501.h"

/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
#define LED_GPIO_PORT CW_GPIOB
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9

int32_t main(void)
{
                uint8_t t = 0;
    GPIO_InitTypeDef GPIO_InitStruct = {0};
                HC_SR501_GPIO_Init();

    RCC_HSI_Enable(RCC_HSIOSC_DIV6);
    __RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStruct.IT = GPIO_IT_NONE;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pins = LED_GPIO_PINS;

    GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);

                OLED_Init();                       
                OLED_Clear();
                t=' ';
                OLED_ShowCHinese(10,0,25);//欢
                OLED_ShowCHinese(18+10,0,26);//迎
                OLED_ShowCHinese(36+10,0,27);//使
                OLED_ShowCHinese(54+10,0,28);//用
                OLED_ShowString(6,3,(uint8_t *)"CW32L031CxTx",16);
                OLED_ShowString(6,6,(uint8_t *)"2023-11-01",16);
                Delay(650000);
                OLED_Clear();
                OLED_ShowCHinese(10,0,29);//芯
                OLED_ShowCHinese(18+10,0,30);//源
                OLED_ShowCHinese(36+10,0,31);//电
                OLED_ShowCHinese(54+10,0,32);//子
                OLED_ShowString(16,3,(uint8_t *)"StartKit REV01",16);
    while (1)
    {
                                OLED_Clear();
                                OLED_ShowChar(48,6,t,16);//ASCII
                                t++;
                                if(t>'~')t=' ';
                                OLED_ShowNum(103,6,t,3,16);//ASCII
                                Delay(650000);
                               
        if (t > '~')
        {
            t = ' ';
        }

                                if(HC_SR501_StateRead()==HC_SR501_LOW)
                                {
                                        GPIO_WritePin(LED_GPIO_PORT,LED_GPIO_PINS,GPIO_Pin_RESET);
                                        Delay(0xFFFF);
                                }
                                else
                                {
                                        GPIO_WritePin(LED_GPIO_PORT,LED_GPIO_PINS,GPIO_Pin_SET);
                                        OLED_Clear();
                                        OLED_DrawBMP(0,0,128,8,BMP3);
                                        Delay(250000);       
                                }
    }
}

/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 循环延时
*
* @param nCount
*/
void Delay(__IO uint32_t nCount)
{
    /* Decrement nCount value */
    while (nCount != 0)
    {
        nCount--;
    }
}
      开发板上的硬件接口连接见下图:

       实测的效果见下面视频,由于HC-SR501红外人体检测模块检测周边环境灵敏度比较高,拍摄时有时候会一直触发“有人经过”的情景。整体来看,监测的效果比较准确,芯源官方提供的底层库函数接口非常标准,很容易移植。最后再提供一份关于OLED屏操作的指引文档。
0.96寸OLED使用文档新手必看V2.0.pdf (1.84 MB)


使用特权

评论回复
沙发
yinwuqing110|  楼主 | 2023-11-4 21:36 | 只看该作者
本帖最后由 yinwuqing110 于 2023-11-4 21:49 编辑

开机启动展示如下:


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

94

主题

1005

帖子

6

粉丝