一、前言
之前到手一块小凌派的板子,附送一个手势传感器,感觉很不错啊,玩起来。
二、小凌派开发板一览
板子还是很不错的,io口丰富,内存也大,可以做很丰富的案例了。
三、搭建开发环境
参考了官方文档,里面要用vbox导入一个虚拟机,我手头上有现成的开发环境,就不用这些步骤了,直接用git把代码拉下来。
git clone https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk2206-openhARMony3.0lts.git
cd lockzhiner-rk2206-openharmony3.0lts
然后配置一下gcc,需要下载gcc编译器。
wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
然后解压出来:
mkdir -p ~/toolchain/
tar -jxvf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 -C ~/toolchain/
设置环境变量:
vim ~/.bashrc
将以下命令拷贝到.bashrc文件的最后一行,保存并退出。
export PATH=~/toolchain/gcc-arm-none-eabi-10.3-2021.10/bin:$PATH
然后使环境变量生效:
source ~/.bashrc
就可以编译了。
hb set -root .
hb set
lockzhiner
lockzhiner-rk2206
选择lockzhiner-rk2206
hb build -f
这里有一个问题,要把shell脚本的shell改成bashell。
sudo dpkg-reconfigure dash
如果没有问题就会显示构建成功,有问题就排查问题。
四、编译手势案例
修改这个文件:vendor/lockzhiner/rk2206/samples/BUILD.gn。
然后修改makefile:device/rockchip/rk2206/sdk_liteos/Makefile。
再执行编译指令,加上-b=release。
hb build -b=release -f
等一会就编出来了。
这里有个问题,如果不加-f的话修改是不生效的,但是加了的话编译很费时间,希望能尽快解决这个问题。
编译完成就下载(需要把u***转到vbox或者vmware去),在开发板上先按下MASKROM按键再按一下RESET按键,再执行下面这个指令。
./flash.py
等一会就下载成功了。
五、运行手势案例
打开你的串口终端软件,查看log信息。
在传感器面前挥挥手就能看到亮灯了,一共支持10种手势,上,下,左,右,离远,离近,顺时针,逆时针,挥手等等。
六、OLED驱动
官方demo里面其实有oled的测试用例,只要准备一块ssd1306的屏幕就行了,对于我一个老鸿蒙来说当然不缺了,立马就找出来一个oled模组出来。
官方的demo在这里:vendor/lockzhiner/rk2206/samples/b5_oled。
只要在BUILD.gn和Makefile里稍微改一下就能运行,但是运行之后发现这个刷新太慢了,一看代码原来没有用缓存的方式。
然后就找来之前玩润和板子的代码,简单来说就是事先把点阵信息用一个大数组存起来,然后刷新的时候只改数据里面的内容,最后再update更新一下所有的点阵数据就行。
不过原来那套代码里用的是润和的i2c接口,现在要改成小凌派的方式:
static uint32_t ssd1306_SendData(uint8_t* data, size_t size)
{
uint32_t ret = LzI2cWrite(OLED_I2C_BUS, OLED_I2C_ADDRESS, data, size);
IF (ret != 0)
{
printf("%s, %s, %d: LzI2cWrite failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
}
return ret;
}
static uint32_t ssd1306_WiteByte(uint8_t regAddr, uint8_t byte)
{
uint8_t buffer[] = {regAddr, byte};
uint32_t ret = LzI2cWrite(OLED_I2C_BUS, OLED_I2C_ADDRESS, buffer, 2);
if (ret != 0)
{
printf("%s, %s, %d: LzI2cWrite failed(%d)!\n", __FILE__, __func__, __LINE__, ret);
}
return ret;
}
// Send a byte to the command register
void ssd1306_WriteCommand(uint8_t byte) {
ssd1306_WiteByte(SSD1306_CTRL_CMD, byte);
}
// Send data
void ssd1306_WriteData(uint8_t* buffer, size_t buff_size) {
uint8_t data[SSD1306_WIDTH * 2] = {0};
for (size_t i = 0; i < buff_size; i++) {
data[i*2] = SSD1306_CTRL_DATA | SSD1306_MASK_CONT;
data[i*2+1] = buffer[i];
}
data[(buff_size - 1) * 2] = SSD1306_CTRL_DATA;
ssd1306_SendData(data, sizeof(data));
}
然后把显示线程配置好就可以显示了:
//oled show and update
static void *OLedTask(const char *arg)
{
(void)arg;
uint32_t ret=0;
ssd1306_Init();
printf("OLedTask queueId=%d\n",queueId);
int text_area_width = 64;
int text_area_height = 64;
int text_per_line_num = text_area_height / font_width;
int mod = hope_num % text_per_line_num;
int text_line_num = hope_num / text_per_line_num;
if (mod)
{
text_line_num += 1;
}
printf("title_addr=%p,dir_addr=%p\n", title_arr,dir_arr);
int text_alredy_show = 0;
int x = 0;
int y = 0;
ssd1306_Fill(Black);
ssd1306_SetCursor(0, 0);
printf("hope_num =%d\n", hope_num);
// int start_num = text_alredy_show * text_per_line_num;
int showed_num = 0;
for (int i = text_alredy_show; i < 14; i++)
{
printf("&title[i]=%p\n",&title_arr[i]);
ssd1306_DrawRegion(x, y, font_height, font_width, title_arr[i], sizeof(title_arr[0]), 0);
x += font_width;
if (x >= text_area_width)
{
y += font_height;
x = 0;
}
showed_num++;
if (y >= text_area_height)
{
break;
}
}
ssd1306_DrawRegion(64, 0, 64, 64, picture_arr, sizeof(picture_arr), 0);
ssd1306_UpdateScreen();
while (1)
{
uint32_t flag = 0;
uint32_t rLen =4;
printf(">>>>>>queueId=%d\n",queueId);
ret = LOS_QueueReadCopy(queueId,
&flag,
&rLen,
LOS_WAIT_FOREVER);
// LOS_Msleep(OLED_INTERVAL_TIME_US);
printf("READ ret = %d,FLAG =%02x\n",ret,flag);
int idx=0;
for(;idx<9;idx++){
if(flag&(1<<idx)){
break;
}
}
printf("x=%d,y=%d,idx=%d,titlearr=%d\n",x, y,idx,sizeof(dir_arr[0]));
// LOS_Msleep(OLED_INTERVAL_TIME_US*5);
ssd1306_DrawRegion(x, y, font_height, font_width, dir_arr[idx], sizeof(dir_arr[0]), 0);
ssd1306_UpdateScreen();
}
return NULL;
}
本来以为能顺顺利利的显示出图形并接收手势传感器发过来的手势信息,结果因为移植的时候有个地方没处理好所以浪费了一些时间,好在官方已经修复这个问题.
七、发送手势
关于手势发送的地方在主线程:
void e53_gs_process(void *arg)
{
unsigned int ret = 0;
unsigned short flag = 0;
e53_gs_init();
while (1)
{
ret = e53_gs_get_gesture_state(&flag);
if (ret != 0)
{
printf(">>Get Gesture Statu: 0x%x\n", flag);
if (flag & GES_UP)
{
printf("\tUp\n");
}
if (flag & GES_DOWM)
{
printf("\tDown\n");
}
if (flag & GES_LEFT)
{
printf("\tLeft\n");
}
if (flag & GES_RIGHT)
{
printf("\tRight\n");
}
if (flag & GES_FORWARD)
{
printf("\tForward\n");
}
if (flag & GES_BACKWARD)
{
printf("\tBackward\n");
}
if (flag & GES_clockWISE)
{
printf("\tClockwise\n");
}
if (flag & GES_COUNT_CLOCKWISE)
{
printf("\tCount Clockwise\n");
}
if (flag & GES_WAVE)
{
printf("\tWave\n");
}
e53_gs_led_up_set((flag & GES_UP) ? (1) : (0));
e53_gs_led_down_set((flag & GES_DOWM) ? (1) : (0));
e53_gs_led_left_set((flag & GES_LEFT) ? (1) : (0));
e53_gs_led_right_set((flag & GES_RIGHT) ? (1) : (0));
e53_gs_led_forward_set((flag & GES_FORWARD) ? (1) : (0));
e53_gs_led_backward_set((flag & GES_BACKWARD) ? (1) : (0));
e53_gs_led_cw_set((flag & GES_CLOCKWISE) ? (1) : (0));
e53_gs_led_ccw_set((flag & GES_COUNT_CLOCKWISE) ? (1) : (0));
e53_gs_led_wave_set((flag & GES_WAVE) ? (1) : (0));
ret = LOS_QueueWriteCopy(queueId,&flag,4, 0);
printf("queue write ret = %d\n",ret);
}
else
{
/* 如果没有数据,则多等待 */
LOS_Msleep(100);
}
}
}
最终效果如上面视频,可以看出对于上下左右的效果很容易测试出来,但是顺时针,逆时针,远,近相对比较难测出来,挥手效果更是难以测试出来,不过好在模块性能够好,最终还是出现了挥手的效果。
八、总结
本次调试板子的过程,不算太顺利,好在及时的解决了,再次给小凌派研发团队点赞。
后期准备制作菜单模块,利用手势拨动菜单项。