一、开篇
感谢主办方提供这次活动,对TencentOS Tiny能有一次全面学习,这次的经历非常不错,从中也学习到了很多知识与经验,讨论群里全国各地开发者也是非常活跃,氛围非常友好。
二、应用场景及主要功能描述:
疫情当下,非接触性地设备启动,应用场景越来越适应市场的需求,手势传感器PAJ7620U2是其中的代表之一,我的大致思路如下:
1. 学习手势传感器PAJ7620U2驱动;
2. 基于TencentOS Tiny CH32V_EVB RISC-V开发套件(采用WCH的RISC-V CH32V307VCT6 MCU)整合手势传感器PAJ7620U2;
3. 借助板载LED灯,做应用的原型产品测试;
三、产品方案设计:
四、硬件及沁恒CH32V307_EVB开发板使用到的引脚
1、手势传感PAJ7620U2
2、CH32V307_EVB开发板
五、部分核心代码:
paj7620u2_iic.h文件:
代码语言:javascript复制#define SDA_GPIO GPIO_Pin_11
#define SDA_PORT GPIOB
#define SDA_RCC RCC_APB2Periph_GPIOB
#define SCL_GPIO GPIO_Pin_10
#define SCL_PORT GPIOB
#define SCL_RCC RCC_APB2Periph_GPIOB
#define DELAY_US(x) Delay_Us(x)
#define DELAY_MS(x) Delay_Ms(x)
//SDA PB11
//SCL PB10
#define SDA_H GPIO_SetBits(SDA_PORT,SDA_GPIO)
#define SDA_L GPIO_ResetBits(SDA_PORT,SDA_GPIO)
#define SDA_R GPIO_ReadInputDataBit(SDA_PORT,SDA_GPIO)
#define SCL_H GPIO_SetBits(SCL_PORT,SCL_GPIO)
#define SCL_L GPIO_ResetBits(SCL_PORT,SCL_GPIO)
u8 GS_Write_Byte(u8 REG_Address,u8 REG_data);
u8 GS_Read_Byte(u8 REG_Address);
u8 GS_Read_nByte(u8 REG_Address,u16 len,u8 *buf);
void GS_i2c_init(void);
void GS_WakeUp(void);
void IIC_SpeedCtl(unsigned short speed);
void SDA_SetGpioMode(uint8_t mode);
void SCL_SetGpioMode(uint8_t mode);
void IIC_delay(uint16_t n);
paj7620u2_iic.c文件:
代码语言:javascript复制//PAJ2670 I2C初始化
void GS_i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SCL_RCC|SDA_RCC,ENABLE);
//SDA
GPIO_InitStructure.GPIO_Pin=SDA_GPIO;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(SDA_PORT,&GPIO_InitStructure);
GPIO_SetBits(SDA_PORT,SDA_GPIO);
//SCL
GPIO_InitStructure.GPIO_Pin=SCL_GPIO;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(SCL_PORT,&GPIO_InitStructure);
GPIO_SetBits(SCL_PORT,SCL_GPIO);
}
/***************************************************************************************************************
*switch SDA GPIO input or output
****************************************************************************************************************/
void SDA_SetGpioMode(uint8_t mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SDA_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=SDA_GPIO;
if(mode==1)
{
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
}
else
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(SDA_PORT,&GPIO_InitStructure);
}
void SCL_SetGpioMode(uint8_t mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SCL_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=SCL_GPIO;
if(mode==1)
{
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
}
else
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(SCL_PORT,&GPIO_InitStructure);
}
//产生IIC起始信号
static void GS_IIC_Start(void)
{
SDA_SetGpioMode(1);
SDA_H;
SCL_H;
Delay_Us(4);
SDA_L;
Delay_Us(4);
SCL_L;
}
//产生IIC停止信号
static void GS_IIC_Stop(void)
{
SDA_SetGpioMode(1);//sda线输出
SCL_L;
SDA_L;
Delay_Us(4);
SCL_H;
SDA_H;
Delay_Us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
static u8 GS_IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_SetGpioMode(0); //SDA设置为输入
SDA_H;Delay_Us(3);
SCL_H;Delay_Us(3);
while(SDA_R)
{
ucErrTime ;
if(ucErrTime>250)
{
GS_IIC_Stop();
return 1;
}
}
SCL_L;
return 0;
}
//产生ACK应答
static void GS_IIC_Ack(void)
{
SCL_L;
SDA_SetGpioMode(1);
SDA_L;
Delay_Us(3);
SCL_H;
Delay_Us(3);
SCL_L;
}
//不产生ACK应答
static void GS_IIC_NAck(void)
{
SCL_L;
SDA_SetGpioMode(1);
SDA_H;
Delay_Us(2);
SCL_H;
Delay_Us(2);
SCL_L;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
static void GS_IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_SetGpioMode(1);
SCL_L;//拉低时钟开始数据传输
for(t=0;t<8;t )
{
if((txd&0x80)>>7)
SDA_H;
else
SDA_L;
txd<<=1;
Delay_Us(5);
SCL_H;
Delay_Us(5);
SCL_L;
Delay_Us(5);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
static u8 GS_IIC_Read_Byte(u8 ack)
{
u8 i,receive=0;
SDA_SetGpioMode(0);//SDA设置为输入
for(i=0;i<8;i )
{
SCL_L;
Delay_Us(4);
SCL_H;
receive<<=1;
if(SDA_R)receive ;
Delay_Us(4);
}
if (!ack)
GS_IIC_NAck();//发送nACK
else
GS_IIC_Ack(); //发送ACK
return receive;
}
//PAJ7620U2写一个字节数据
u8 GS_Write_Byte(u8 REG_Address,u8 REG_data)
{
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID);
if(GS_IIC_Wait_Ack())
{
GS_IIC_Stop();//释放总线
return 1;//没应答则退出
}
GS_IIC_Send_Byte(REG_Address);
GS_IIC_Wait_Ack();
GS_IIC_Send_Byte(REG_data);
GS_IIC_Wait_Ack();
GS_IIC_Stop();
return 0;
}
//PAJ7620U2读一个字节数据
u8 GS_Read_Byte(u8 REG_Address)
{
u8 REG_data;
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID);//发写命令
if(GS_IIC_Wait_Ack())
{
GS_IIC_Stop();//释放总线
return 0;//没应答则退出
}
GS_IIC_Send_Byte(REG_Address);
GS_IIC_Wait_Ack();
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID|0x01);//发读命令
GS_IIC_Wait_Ack();
REG_data = GS_IIC_Read_Byte(0);
GS_IIC_Stop();
return REG_data;
}
//PAJ7620U2读n个字节数据
u8 GS_Read_nByte(u8 REG_Address,u16 len,u8 *buf)
{
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID);//发写命令
if(GS_IIC_Wait_Ack())
{
GS_IIC_Stop();//释放总线
return 1;//没应答则退出
}
GS_IIC_Send_Byte(REG_Address);
GS_IIC_Wait_Ack();
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID|0x01);//发读命令
GS_IIC_Wait_Ack();
while(len)
{
if(len==1)
{
*buf = GS_IIC_Read_Byte(0);
}
else
{
*buf = GS_IIC_Read_Byte(1);
}
buf ;
len--;
}
GS_IIC_Stop();//释放总线
return 0;
}
//PAJ7620唤醒
void GS_WakeUp(void)
{
GS_IIC_Start();
GS_IIC_Send_Byte(PAJ7620_ID);//发写命令
GS_IIC_Stop();//释放总线
}
paj7620u2.c文件:
代码语言:javascript复制//手势识别测试
void Gesture_test(void)
{
u8 i;
u8 status;
u8 key;
u8 data[2]={0x00};
u16 gesture_data;
u8 ledflash=0;
paj7620u2_selectBank(BANK0);//进入BANK0寄存器区域
for(i=0;i<GESTURE_SIZE;i )
{
GS_Write_Byte(gesture_arry[i][0],gesture_arry[i][1]);//手势识别模式初始化
}
paj7620u2_selectBank(BANK0);//切换回BANK0寄存器区域
i=0;
LCD_Fill(30,170,300,300,WHITE);
LCD_ShowString(0,70,"--- Gesture show ---",WHITE,BLACK,16,0);
while(1)
{
status = GS_Read_nByte(PAJ_GET_INT_FLAG1,2,&data[0]);//读取手势状态
if(!status)
{
gesture_data =(u16)data[1]<<8 | data[0];
if(gesture_data)
{
switch(gesture_data)
{
case GES_UP:
LCD_ShowString(0,100,"UP: ",WHITE,BLACK,32,0);
LCD_ShowString(0,130," LED1 ON ",WHITE,BLACK,32,0);
printf("Uprn");
ledflash=1;
GPIO_WriteBit(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5, 1);
GPIO_WriteBit(GPIOE, GPIO_Pin_2, 0);
break; //向上
case GES_DOWM:
LCD_ShowString(0,100,"Dowm: ",WHITE,BLACK,32,0);
LCD_ShowString(0,130," LED2 ON ",WHITE,BLACK,32,0);
printf("Dowmrn");
ledflash=1;
GPIO_WriteBit(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5, 1);
GPIO_WriteBit(GPIOE, GPIO_Pin_3, 0);
break; //向下
case GES_LEFT:
LCD_ShowString(0,100,"Left: ",WHITE,BLACK,32,0);
LCD_ShowString(0,130," LED3 ON ",WHITE,BLACK,32,0);
printf("Leftrn");
ledflash=1;
GPIO_WriteBit(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5, 1);
GPIO_WriteBit(GPIOE, GPIO_Pin_4, 0);
break; //向左
case GES_RIGHT:
LCD_ShowString(0,100,"Right: ",WHITE,BLACK,32,0);
LCD_ShowString(0,130," LED4 ON ",WHITE,BLACK,32,0);
printf("Rightrn");
ledflash=1;
GPIO_WriteBit(GPIOE, GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5, 1);
GPIO_WriteBit(GPIOE, GPIO_Pin_5, 0);
break; //向右
default: LCD_ShowString(0,100,"check ",WHITE,BLACK,16,0);
ledflash=0; break;
}
}
}
Delay_Ms(300);
i ;
printf("### check %drn",i);
if(i==500)
{
//LED0=!LED0;//提示系统正在运行
i=0;
}
}
}
源代码项目工程文件:
六、视频展示:
https://www.bilibili.com/video/BV1MP411L7K4 B站链接