官网代码仓:BearPi-HM_Nano: 小熊派BearPi-HM Nano开发板基于HarmonyOS的源码
代码仓和全网几乎没有hi3861SPI相关的例程序,故分享给大家(首发哈哈)
这个是代码的效果视频
ws2812
驱动ws2812灯板关键点为实现ws2812时序的0/1码
在liteos上我想到有三种方法
1.GPIO翻转
实时性不够,实测的不能得到400ns宽度(0码的脉宽)的电平
2.PWM占空比
没有找到dma发送的接口(不能连续发送多个字节),每次只能设置一个占空比,现象为连续多个相同占空比的电平
3.SPI发数据
理想情况下800K*8HZ发送一个字节(8bit)模拟ws2812一个时序周期
发送0xFC(11111100)时为‘1码’
发送0xE0 (11100000)时为‘0码’
发送0x00时为低电平,用作break/reset(MOSI空闲时为高电平),放在每帧开始
以下为接线图
以下为源码
spi_example.c
#include <stdio.h>
#include <string.h>
#include "hi_gpio.h"
#include "hi_spi.h"
#include <hi_io.h>
#include <unistd.h>#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_spi.h"
#include "wifiiot_gpio_ex.h"
#define RED_INDEX 0
#define GREEN_INDEX 1
#define BLUE_INDEX 2//功能:把 3BYTE 的RGB数据转换成 24BYTE SPI数据
static void WS2812_send(unsigned char *rgb)
{unsigned char data[24];unsigned char i, bit;unsigned char index = 0;for(i = 0; i < 8; i++) // GREEN 按位发送{bit = ((rgb[GREEN_INDEX] << i) & 0x80);data[index] = (bit == 0x80) ? 0xfc : 0xe0;//spi发送0xfc 为ws812 1码 spi发送0xe0 为ws812 0码index++;} for(i = 0; i < 8; i++) // RED{bit = ((rgb[RED_INDEX]<<i) & 0x80);data[index] = (bit==0x80) ? 0xfc : 0xe0;index++;}for(i=0; i<8; i++) // BLUE{bit = ((rgb[BLUE_INDEX]<<i) & 0x80);data[index] = (bit==0x80) ? 0xfc : 0xe0;index++;}hi_spi_host_write(WIFI_IOT_SPI_ID_0, data, 24);
}
//色带
unsigned char color[8][3]=
{{255,255,255},//白{255,255, 0 },{255, 0 ,255},{ 0 ,255,255},{ 0 , 0 ,255},//蓝{ 0 ,255, 0 },//绿{255, 0 , 0 },//红{ 0 , 0 , 0 }
};static void WS2812Task(void)
{//初始化GPIOGpioInit();hi_spi_deinit(HI_SPI_ID_0); /* if wake_up from deep sleep, should deinit first */hi_spi_cfg_basic_info spi_cfg_basic_info;spi_cfg_basic_info.cpha = 0;spi_cfg_basic_info.cpol = 0;spi_cfg_basic_info.data_width = HI_SPI_CFG_DATA_WIDTH_E_8BIT;spi_cfg_basic_info.endian = 0;spi_cfg_basic_info.fram_mode = 0;spi_cfg_basic_info.freq = 8*900000; hi_spi_cfg_init_param spi_init_param = {0};spi_init_param.is_slave = 0;hi_spi_init(HI_SPI_ID_0, spi_init_param, &spi_cfg_basic_info); //基本参数配置hi_spi_set_loop_back_mode(HI_SPI_ID_0, 1);hi_io_set_func(HI_IO_NAME_GPIO_12, HI_IO_FUNC_GPIO_12_SPI0_CSN);//io配置hi_io_set_func(HI_IO_NAME_GPIO_10, HI_IO_FUNC_GPIO_10_SPI0_CK);hi_io_set_func(HI_IO_NAME_GPIO_11, HI_IO_FUNC_GPIO_11_SPI0_RXD);hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_SPI0_TXD);hi_io_set_driver_strength(HI_IO_NAME_GPIO_6, HI_IO_DRIVER_STRENGTH_2);//驱动能力hi_spi_set_irq_mode(HI_SPI_ID_0, 0);hi_spi_set_dma_mode(HI_SPI_ID_0, 1);unsigned char data[50];unsigned char rgb[3];unsigned int i;while (1){for (i = 0; i < 256; i ++){memset(data, 0, sizeof(data));hi_spi_host_write(WIFI_IOT_SPI_ID_0, data, sizeof(data));//前50byte为低电平breakfor (unsigned int j = 0; j < 256; j ++)//亮度{rgb[0] = color[i%7][0]&j;//色带rgb[1] = color[i%7][1]&j;rgb[2] = color[i%7][2]&j;for (unsigned int k = 0; k < 256; k ++)//控制256个灯WS2812_send(rgb);usleep(10 * 1000);}}i = 0;}
}static void WS2812ExampleEntry(void)
{osThreadAttr_t attr;attr.name = "WS2812Task";attr.attr_bits = 0U;attr.cb_mem = NULL;attr.cb_size = 0U;attr.stack_mem = NULL;attr.stack_size = 1024;attr.priority = osPriorityAboveNormal6 ;if (osThreadNew((osThreadFunc_t)WS2812Task, NULL, &attr) == NULL)//创建线程{printf("Falied to create WS2812Task!\n");}
}APP_FEATURE_INIT(WS2812ExampleEntry);
BUILD.gn
static_library("spi_example") {sources = ["spi_example.c","//ohos_bundles/@bearpi/hm_nano_hi3861/platform/drivers/spi/hi_spi.c","//ohos_bundles/@bearpi/hm_nano_hi3861/platform/drivers/spi/spi.c",]include_dirs = ["//utils/native/lite/include","//kernel/liteos_m/components/cmsis/2.0","//base/iot_hardware/interfaces/kits/wifiiot_lite","//ohos_bundles/@bearpi/hm_nano_hi3861/include",]
}