前言
目前正在打大学生嵌入式大赛,本人负责的部分是对Hi3861开发板进行开发,因为以前玩的更多的是STM32,所以产生的idea会先在STM32上实现再试着转移到Hi3861开发板上,这其实符合大部分日嵌入式开发玩家的流程开发。
提示:下面案例可供参考
一、Hi3861是什么?
Hi3861其实并不是华为独自研发的,Hi3861是润和开发的一款开发板,华为海思和他们是一个合作的关系。
Hi3861LV100是一款高度集成的2.4GHz WiFi SoC芯片,集成IEEE 802.11b/g/n基带和RF电路,RF电路包括功率放大器PA、低噪声放大器LNA、RF balun、天线开关以及电源管理等模块;支持20MHz标准带宽和5MHz/10MHz窄带宽,提供最大72.2Mbit/s物理层速率。
Hi3861LV100WiFi基带支持正交频分复用(OFDM)技术,并向下兼容直接序列扩频(DSSS)和补码键控(CCK)技术,支持IEEE 802.11b/g/n协议的各种数据速率。
Hi3861LV100芯片集成高性能32bit微处理器、硬件安全引擎以及丰富的外设接口,外设接口包括SPI、UART、I2C、PWM、GPIO和多路ADC,同时支持高速SDIO2.0
Slave接口,最高时钟可达50MHz;芯片内置SRAM和Flash,可独立运行,并支持、在Flash上运行程序。
Hi3861LV100支持Huawei LiteOS和第三方组件,并配套提供开放、易用的开发和调试运行环境。
Hi3861LV100芯片适应于智能家电、智能门锁、低功耗Camera、BUTTON等物联网低功耗智能产品领域。
二、使用步骤
1.写一个STM32程序
首先,一个STM32的程序怎么转移过去一个其他的板子呢?(本文为Hi3861)
- 需要看两个板子对应的引脚,本文转移的是一个ADC读取传感器电压变化值的代码,那么首先需要看的就是Hi3861哪些引脚支持ADC功能复用,也就是能不能用这个引脚读取电压值。
- 其次需要看第二个板子的要怎么设置,比如STM32写代码通常需要导包(相应的系统包)、设置魔法棒(path路径等),两者对比的设置如下两图所示。
3. 在导入对应的代码包(如adc.h此类),建议Hi3861直接用一个官方给的Hello world例程开发,这样就省去了很多和STM32一样的导包麻烦啦
4. 导包完成就是配置Hi3861支持的库了(专业名称BSP(板级支持包))。这一步很重要!这一步很重要!这一步很重要!如果你要使用Hi3861的相应功能但是你没有勾选支持的BSP的话,代码写对了也没用!比如要写一个OLED的显示功能,那么必须勾选IIC的support。
2.如何转移到Hi3861
弄完了基础的配置之后就是如何转移代码的问题了。我直接贴上一部分的代码分析,有需要的自行去文章末尾下载工程文件
STM32代码如下:
int main(void)
{
u16 adcx;
float temp;
u8 lcd_id[12]; //存放LCD ID字符串
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
Adc_Init(); //ADC初始化
LCD_Init();
sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"Elite STM32");
LCD_ShowString(60,70,200,16,16,"ADC TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2015/1/14");
//显示提示信息
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,130,200,16,16,"ADC_CH0_VAL:");
LCD_ShowString(60,150,200,16,16,"ADC_CH0_VOL:0.000V");
while(1)
{
adcx=Get_Adc_Average(ADC_Channel_1,10);
LCD_ShowxNum(156,130,adcx,4,16,0);//显示ADC的值
temp=(float)adcx*(3.3/4096);
adcx=temp;
LCD_ShowxNum(156,150,adcx,1,16,0);//显示电压值
temp-=adcx;
temp*=1000;
LCD_ShowxNum(172,150,temp,3,16,0X80);
LED0=!LED0;
delay_ms(250);
LED0=!LED0;
delay_ms(1000);
}
}
//此处直接用的是正点原子的官方ADC例程,主要是为了转移的思想,转移什么代码不重要
这个代码主要的步骤就是初始化需要采集电压引脚,配置ADC,拿到模拟量之后用函数转移为数字量(ADC过程)显示到LCD上。代码的思想很简单
Hi3861代码如下:
#include <hi_early_debug.h>
#include <hi_task.h>
#include <stdio.h>
#include <hi_adc.h>
#include <hi_gpio.h>
#include <hi_io.h>
#include <hi_stdlib.h>
#include <hi_i2c.h>
#include <ssd1306_oled.h>
#define WATER_SENSOR_TASK_SIZE ( 1024*2 )
#define WATER_SENSOR_TASK_PRIO ( 28 )
#define ADC_LENGTH ( 20 )
#define VLT_MIN (100)
hi_u16 g_water_sensor_adc_buf[ADC_LENGTH];
extern hi_u32 oled_init(hi_void);
extern hi_void oled_show_str(hi_u8 x, hi_u8 y, hi_u8 *chr, hi_u8 char_size);
/*
@berf gpio_config:i2c 0 Pin reuse is I2C mode
*/
hi_void gpio_config() {
hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
}
/*
@berf oled Screen display initialization
@param hi_void
*/
hi_void water_sensor_display(hi_void)
{
hi_i2c_init(HI_I2C_IDX_0, HI_I2C_IDX_BAUDRATE); /* baudrate: 400kbps */
hi_i2c_set_baudrate(HI_I2C_IDX_0, HI_I2C_IDX_BAUDRATE);
oled_init();
oled_fill_screen(OLED_CLEAN_SCREEN);//clear screen
}
/*
gpio init Pin initialization
*/
hi_void water_sensor_gpio_init(hi_void)
{
hi_io_set_func(HI_IO_NAME_GPIO_7, HI_IO_FUNC_GPIO_7_GPIO);
hi_gpio_set_dir(HI_GPIO_IDX_7, HI_GPIO_DIR_IN);
}
hi_void *water_sensor(hi_void *param)
{
hi_u32 ret;
hi_u16 data;
float voltage;
hi_float vlt_max = 0;
hi_float vlt_min = VLT_MIN;
hi_u32 i;
while (1) {
memset_s(g_water_sensor_adc_buf, sizeof(g_water_sensor_adc_buf), 0x0, sizeof(g_water_sensor_adc_buf));
for (i = 0; i < ADC_LENGTH; i++) {
vlt_max =0;
ret = hi_adc_read(HI_ADC_CHANNEL_3, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0xF0); //CHANNAL 3 GPIO 7
if (ret != HI_ERR_SUCCESS) {
printf("ADC Read Fail\n");
return HI_NULL;
}
printf("adc original data %d \n", data);
voltage = (float)data * 1.8 * 4 / 4096.0; /* vlt * 1.8 * 4 / 4096.0 is to convert codeword to voltage */
vlt_max = (voltage > vlt_max) ? voltage : vlt_max;
vlt_min = (voltage < vlt_min) ? voltage : vlt_min;
printf( "vlt_min:%.3f, vlt_max:%.3f \n", vlt_min, vlt_max );
if (vlt_max > 1) {
oled_show_str(0, 4, "is Rainning", 16);/*The test results will be displayed on the screen, if moisture is detected, it will display "it's raining"*/
} else if (vlt_max < 1) {
oled_show_str(0, 4, "a sunny day", 16);/*The test results will be displayed on the screen, if no moisture is detected, "sunny" will be displayed”*/
}
}
hi_sleep(100);
}
}
/*
@berf Create simulated moisture sensor task
@param hi_void
@return Task created successfully ret = HI_ERR_SUCCESS,Failed ret = 0x800xxxx
*/
hi_u32 water_sensor_task(hi_void)
{
hi_u32 ret;
hi_task_attr attr ={0};
hi_u32 water_sensor_id;
gpio_config();
/*adc gpio init*/
water_sensor_gpio_init();
/*oled display*/
water_sensor_display();
/*attr Configuration of structural parameters*/
attr.stack_size = WATER_SENSOR_TASK_SIZE;//Task stack memory
attr.task_prio = WATER_SENSOR_TASK_PRIO;//The task priority ranges from 0 to 31. Tasks 0 to 10 should not be used. The SDK has been used. The higher the value, the lower the priority
attr.task_name = (hi_char*)"water_sensor_task";//task name
/*create task*/
ret = hi_task_create(&water_sensor_id, &attr, water_sensor, HI_NULL);
if (ret != HI_ERR_SUCCESS) {
printf("Failed to create water_sensor_task\r\n");
}
return HI_ERR_SUCCESS;
}
这个代码是拿官方写的一个adc例程(此处我怕贴我自己写的不好讲清楚)
可以看到Hi3861和STM32最大的不同点就是Hi3861采用的是多线程执行方式,STM32采用的是顺序执行方式。所以正规的开发Hi3861的流程是:先创建一个线程任务,即create task,然后将需要实现的放入到线程任务跳转的功能函数中。
例:/create task/
ret = hi_task_create(&water_sensor_id, &attr, water_sensor, HI_NULL);
其中water_sensor是功能函数。
没了解过多线程单片机系统开发的先不要纠结为什么这么写,先学会用!照猫画虎
钢铁侠说过:有时候学会走之前要先试着跑起来!(是这么说的嘛我不记得了,大概大概 )
Hi3861中的hi_adc_read函数,这些就需要去看API文档和相关硬件设计的文档了。这里附上一些我接触过了引脚复用为ADC的
1.ret = hi_adc_read(HI_ADC_CHANNEL_3, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0xF0); //CHANNAL 3 GPIO 7
2.ret = hi_adc_read(HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0); //CHANNAL 2 GPIO 5
3.ret = hi_adc_read(HI_ADC_CHANNEL_5, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0xF0); //CHANNAL 5 GPIO 11
里面的参数设计就需要看API文档了,我贴心 的给大家准备好了
总结
本文介绍了怎么把一个STM32的程序转移到Hi3861上,其实这个思想适用于大多数的转移开发板代码。