启航KS_IoT智能开发套件案例及代码之二

系统教程10个月前发布 hanxin2001
6 0 0

启航KS_IoT智能开发套件案例及代码之二

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://harmonyos.51cto.com​

案例简介

启航KS包括1块核心板和4块扩展板,本文档包括以下功能案例:

启航KS核心板实现的案例

  • OLED显示
  • 温湿度监测
  • 超声波测距
  • 人体红外感应
  • 电机控制
  • 蜂鸣器
  • 光照强度监测
  • 按键功能
  • RGB呼吸灯
  • NFC
  • Wi-Fi
  • 光电开关监测
  • 可燃气体监测

启航KS扩展板实现的案例

  • PM2.5监测
  • 甲醛监测
  • BDS/GPS定位
  • 姿态监测

启航KS核心板功能实现

核心板功能区分布图如下:

启航KS_IoT智能开发套件案例及代码之二

RGB呼吸灯功能实现

RGB呼吸灯功能原理

RGB呼吸灯功能是通过循环控制PWM占空比,调节LED亮度,实现RGB呼吸灯效果。

RGB呼吸灯硬件接口

RGB

启航KS_IoT智能开发套件案例及代码之二

按键控制使用的GPIO接口为GPIO10, GPIO11, GPIO12。其引脚连接说明如下:

  • RED —– GPIO12
  • BLUE —– GPIO10
  • GREEN —– GPIO11

RGB呼吸灯功能中,GPIO10、GPIO11、GPIO12引脚配置设置见4.6章节

用跳线帽连接下图原理图中紫色方框位置

启航KS_IoT智能开发套件案例及代码之二

RGB呼吸灯功能软件实现

代码目录:

applications\sample\wifi-iot\app\issdemo
|—iss_led
|—iss_led.c
|—iss_led.h

1、配置GPIO引脚为PWM

uint32_t IssInitLedByPwmPinFunc(hi_pwm_port pwmPort, hi_gpio_idx gpioIdx, hi_io_name ioName,                               hi_io_func_gpio_10 gpioFunc)
{
uint32_t state = HI_ERR_FAILURE;
state = hi_pwm_init(pwmPort);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "init pwm failure.state=0x%x", state);
// Set the function of the specified pin as PWM output
state = hi_io_set_func(ioName, gpioFunc);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "io set GPIO failure.state=0x%x", state);
// Sets the direction of the pin to output
state = IoTGpioSetDir(gpioIdx, HI_GPIO_DIR_OUT);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "io set dir failure.state=0x%x", state);
return HI_ERR_SUCCESS;
}

2、PWM配置

配置PWM1,PWM2,PWM3的硬件引脚

uint32_t IssInitLedByPwm(void)
{
uint32_t state = HI_ERR_FAILURE;
state = IssInitLedByPwmPinFunc(HI_PWM_PORT_PWM1, HI_GPIO_IDX_10, HI_IO_NAME_GPIO_10,
HI_IO_FUNC_GPIO_10_PWM1_OUT);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "IssInitLedByPwmPinFunc HI_PWM_PORT_PWM1 failure.state=0x%x", state);
state = IssInitLedByPwmPinFunc(HI_PWM_PORT_PWM2, HI_GPIO_IDX_11, HI_IO_NAME_GPIO_11,
HI_IO_FUNC_GPIO_11_PWM2_OUT);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "IssInitLedByPwmPinFunc HI_PWM_PORT_PWM2 failure.state=0x%x", state);
state = IssInitLedByPwmPinFunc(HI_PWM_PORT_PWM3, HI_GPIO_IDX_12, HI_IO_NAME_GPIO_12,
HI_IO_FUNC_GPIO_12_PWM3_OUT);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "IssInitLedByPwmPinFunc HI_PWM_PORT_PWM3 failure.state=0x%x", state);
return HI_ERR_SUCCESS;
}

3、PWM启动

uint32_t IssPwmOut(hi_pwm_port pwmPort, uint16_t duty, uint32_t freq)
{
uint32_t state = HI_ERR_FAILURE;
state = hi_pwm_start(pwmPort, duty, freq); /* duty: 750 freq:1500 scope:1~65535*/
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "pwm start failure.state=0x%x", state);
return HI_ERR_SUCCESS;
}

4、RGB呼吸灯开关控制

通过PWM打开所有RGB呼吸灯

uint32_t IssTurnOnAllLedByPwm()
{
// PWM is used to control the light on
uint32_t state = HI_ERR_FAILURE;
state = IssPwmOut(HI_PWM_PORT_PWM1, 40000, 40000);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM1 failure,state=0x%x", state);
state = IssPwmOut(HI_PWM_PORT_PWM2, 40000, 40000);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM2 failure,state=0x%x", state);
state = IssPwmOut(HI_PWM_PORT_PWM3, 40000, 40000);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM3 failure,state=0x%x", state);
return HI_ERR_SUCCESS;
}

通过PWM关闭所有RGB呼吸灯

uint32_t IssTurnOffAllLedByPwm()
{
// PWM is used to control the lamp off
uint32_t state = HI_ERR_FAILURE;
state = IoTPwmStop(HI_PWM_PORT_PWM1);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM1 failure,state=0x%x", state);
state = IoTPwmStop(HI_PWM_PORT_PWM2);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM2 failure,state=0x%x", state);
state = IoTPwmStop(HI_PWM_PORT_PWM3);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "HI_PWM_PORT_PWM3 failure,state=0x%x", state);
return HI_ERR_SUCCESS;
}

NFC感应器实现

NFC感应器原理

NFC感应器,型号为FM11NC8,实现NFC感应器控制。

NFC 是一种近场无线通信技术,通信距离理论上可以在 10cm(实际中需要贴的很近),以13.56MHz RFID 技术为基础,与现有的非接触式智能卡国际标准相兼容。 数据传输速率 106kbit/s、212kbit/s、424kbit/s。

通信原理是基于感应近场,在近场区域内感应场强弱与电磁辐射源以及天线的距离相关,近则强远则弱。

NFC 通信一般有两种模式:主动模式和被动模式。

  • 主动模式:两个设备发起端(标签设备)和目标端(读卡器)都必须发射出本身的射频场,以实现向对方系统设备之间发送数据。
  • 被动模式:相对于主动模式,被动模式只有一方提供射频场,提供射频场的都是通信发起端设备,另一端目标不需要产生射频场,目标设备能量的产生由发起方射频场的感应电动势进行供电,目标端使用负载调制的方式,以相同的速率将数据回传给发起端设备。在整个双方通信过程中发起方设备的射频场必须存在,一旦关闭目标端设备的供电就会结束,数据交换无法进行。

本案例采用被动模式。

NFC感应器硬件接口

NFC

启航KS_IoT智能开发套件案例及代码之二

NFC采用I2C协议进行数据通信。使用的GPIO 引脚分别是 GPIO13,GPIO14,其引脚连接说明如下:

  • SDA —– GPIO13
  • SCL —– GPIO14

用跳线帽连接下图原理图中紫色方框位置

启航KS_IoT智能开发套件案例及代码之二

NFC感应器软件实现

NFC 软件驱动实现:

代码目录:

applications\sample\wifi-iot\app\issdemo
|—iss_nfc
|—iss_nfc_demo.c
|—iss_nfc_demo.h
|—iss_nfc_interface.c
|—iss_nfc_interface.h
|—iss_nfc_regvalue.c
|—iss_nfc_regvalue.h

NFC初始化

I2C硬件引脚IDX_0 初始化

  • 设置I2C波特率
  • 设置GPIO13为I2C0SDA
  • 设置GPIO14为I2C0SCL

NFC和OLED使用共同的I2C0接口,在OLED模块中已初始化,这里不需要重复初始化

NFC驱动实现

寄存器读写接口实现

u32 WriteRead(u16 reg, u8 *recvData, u8 sendLen, u8 readLen)
{
hi_i2c_data readBuffer = {0};
u8 userCmd[2] = {(reg & 0xFF00) >> 8, reg & 0x00FF};
memset(recvData, 0x0, sizeof(recvData));
memset(&readBuffer, 0x0, sizeof(hi_i2c_data));
readBuffer.send_buf = userCmd;
readBuffer.send_len = sendLen;
readBuffer.receive_buf = recvData;
readBuffer.receive_len = readLen;
hi_i2c_writeread(NFC_I2C_CHANNEL, ISS_CHIP_NFC_ADDR & 0xFE, &readBuffer);
return 0;
}
/**********************************************
* nfc interface write register buffer
**********************************************/
u32 WriteBuffToReg(u16 reg, u8 *dataBuff, u8 len)
{
hi_i2c_data writeBuffer = {0};
u8 userCmd[64] = {(reg & 0xFF00) >> 8, reg & 0x00FF};

writeBuffer.send_buf = userCmd;
writeBuffer.send_len = 2 + len;
for (u8 i = 0; i < len; i++) {
userCmd[2 + i] = *(dataBuff + i);
}
IoTI2cWrite(NFC_I2C_CHANNEL, ISS_CHIP_NFC_ADDR & 0xFE, writeBuffer.send_buf, writeBuffer.send_len);
return 0;
}
/**********************************************
* nfc interface write register byte
**********************************************/
u32 WriteByteToReg(u16 reg, u8 dataBuff)
{
hi_i2c_data writeBuffer = {0};
u8 userCmd[64] = {(reg & 0xFF00) >> 8, reg & 0x00FF, dataBuff};
writeBuffer.send_buf = userCmd;
writeBuffer.send_len = 3;

IoTI2cWrite(NFC_I2C_CHANNEL, ISS_CHIP_NFC_ADDR & 0xFE, writeBuffer.send_buf, writeBuffer.send_len);
return 0;
}
/**********************************************
* nfc interface write buffer
**********************************************/
u32 WriteBuffer(u8 *dataBuff, u8 len)
{
hi_i2c_data writeBuffer = {0};
u8 userCmd[128] = {0};
memset(userCmd, 0x0, sizeof(userCmd));
userCmd[0] = 0xff;
userCmd[1] = 0xf0;
for (int i = 0; i < len; i++) {
userCmd[2 + i] = *(dataBuff + i);
}
writeBuffer.send_buf = userCmd;
writeBuffer.send_len = 2 + len;
hi_i2c_writeread(NFC_I2C_CHANNEL, ISS_CHIP_NFC_ADDR & 0xFE, &writeBuffer);
return 0;
}

读取中断标志

void ReadNfcIrqFlag(u8 *flag)
{
u8 irqFlag = 0;
u8 ret = 0;
irqFlag = ChipControl.readReg(ISS_MAIN_IRQ);
if (irqFlag & ISS_MAIN_IRQ_FIFO) {
ret = ChipControl.readReg(ISS_FIFO_IRQ);
if (ret & ISS_FIFO_IRQ_WL) {
flag[1] = 1;
}
}
if (irqFlag & ISS_MAIN_IRQ_AUX) {
ret = ChipControl.readReg(ISS_AUX_IRQ);
ChipControl.writeReg(ISS_FIFO_FLUSH, 0xFF);
}
if (irqFlag & ISS_MAIN_IRQ_RX_START) {
flag[0] = 1;
}
if (irqFlag & ISS_MAIN_IRQ_RX_DONE) {
flag[2] = 1;
}
}

读取缓冲区

u32 ChipDataRecv(u8 *revBuffer)
{
u8 flag[3] = {0};
u32 revLen = 0;
u32 lastCount = 0;
(void)revBuffer;
flag[1] = 0;
ReadNfcIrqFlag(flag);
if ((flag[0] == 1) && (flag[1] == 1)) {
flag[1] = 0;
ChipReadFifo(FIFO_MAX_COUNT, &revBuffer[revLen]);
revLen += FIFO_MAX_COUNT;
}
if (flag[2] == 1) {
lastCount = (u32)(ChipControl.readReg(ISS_FIFO_WORDCNT) & 0x3F);
ChipReadFifo(lastCount, &revBuffer[revLen]);
revLen = revLen + lastCount;
flag[0] = 0;
}
if (revLen <= 2) {
return 0;
}
return (revLen - 2);
}

读取卡数据

u8 AppI2cNfcMaster(BoardEnvInfoValue *info)
{
u8 cardLen = 0;
static u8 cardValid = 0;
static u8 oldCardValid = 0xff;
static u16 timeOut = 0;
cardLen = ChipControl.dataRecv(readCardFifo);
timeOut++;
if (cardLen > 0) {
timeOut = 0;
cardValid = 1;
printf("nfc 1\r\n");
if (cardValid != oldCardValid) {
oldCardValid = cardValid;
info->nfcState = 1;
return 0;
}
}
if (timeOut > 20) {
timeOut = 0;
cardValid = 0;
oldCardValid = 0xff;
info->nfcState = 0;
}
return 0;
}

Wi-Fi功能实现

Wi-Fi功能原理

Wi-Fi模组集成在Hi3861中,可以工作在STA,也可以工作在AP。

工作在STA时,启航KS要连接上指定的热点(可用手机做热点测试);工作在AP状态时,手机可以连接启航KS生成的热点。

Wi-Fi功能软件实现

代码目录:

applications\sample\wifi-iot\app\issdemo\
|---iss_thread
|---iss_wifi_sta.c
|---iss_wifi_sta.h
|---iss_wifi
|---iss_udp_server.c
|---iss_udp_server.h
1、初始化Wi-Fi配置
uint32_t IssInitWifiConfig(void)
{
uint32_t state = HI_ERR_FAILURE;
char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};
int len = sizeof(ifname);
state = hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "hi_wifi_init failure.state=0x%x", state);
state = hi_wifi_sta_start(ifname, &len);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "wifi sta start failure.state=0x%x", state);
/* register call back function to receive wifi event, etc scan results event,
* connected event, disconnected event.
*/
g_lwip_netif = netifapi_netif_find(ifname);
RUNTIME_ERR_RET_FAIL(g_lwip_netif == NULL, "netifapi_netif_find failure.state=0x%x", state);
state = hi_wifi_register_event_callback(IssWifiWpaEventCallback);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "wifi register event callback failure.state=0x%x", state);
return state;
}

连接热点

int hi_wifi_start_connect(char *ssid, char *key, hi_wifi_auth_mode auth_mode)
{
hi_wifi_assoc_request assoc_req = {0};
/* copy SSID to assoc_req */
if (memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, ssid, HI_WIFI_MAX_SSID_LEN) != EOK) {
printf("%s memcpy_s failed\r\n", __func__);
return HISI_FAIL;
}
/* copy KEY to assoc_req */
if (memcpy_s(assoc_req.key, HI_WIFI_MAX_KEY_LEN + 1, key, strlen(key)) != EOK) {
printf("%s memcpy_s failed\r\n", __func__);
return HISI_FAIL;
}
/*
* OPEN mode
* for WPA2-PSK mode:
* set assoc_req.auth as HI_WIFI_SECURITY_WPA2PSK,
* then memcpy(assoc_req.key, "12345678", 8).
*/
assoc_req.auth = auth_mode;

if (hi_wifi_sta_connect(&assoc_req) != HISI_OK) {
return HISI_FAIL;
}
return HISI_OK;
}

启动UDP server

void StartUdpServer(void)
{
struct sockaddr_in servaddr;
int socketHandle = socket(PF_INET, SOCK_DGRAM, 0);
// server ip port
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT_8088);
bind(socketHandle, (struct sockaddr *)&servaddr, sizeof(servaddr));
while (TRUE) {
PSocketData pSocketData = (PSocketData)malloc(sizeof(SocketData));
memset(pSocketData, 0, sizeof(SocketData));
pSocketData->socketHandle = socketHandle;
int sizeClientAddr = sizeof(struct sockaddr_in);
printf("wait recvfrom...\r\n");
int ret = recvfrom(socketHandle, pSocketData->recvBuf, SOCKET_BUF_SIZE, 0,
(struct sockaddr *)&pSocketData->addrClient, (socklen_t *)&sizeClientAddr);
RUNTIME_ERR_CONTINUE_WITH_LOG(ret <= 0, "recvfrom Execute failed.");
printf(":::::::::::\t recvBuf=%s.::::::::::::\r\n", pSocketData->recvBuf);
CreateUdpHandleThread(pSocketData);
usleep(20);
}
}

光电开关监测实现

光电开关监测原理

光电开关是用硫化镉或硒化镉等半导体材料制成的特殊电阻器,其工作原理是基于内光电效应。光照愈强,阻值就愈低,随着光照强度的升高,电阻值迅速降低。

光电开关硬件接口

PHO_RES

启航KS_IoT智能开发套件案例及代码之二

引脚连接说明如下:

光敏传感器使用的GPIO接口为GPIO06

用跳线帽连接下图原理图中紫色方框位置

启航KS_IoT智能开发套件案例及代码之二

额外功能说明:

光电开关联动光照灯D6,需要按下SW1。当光电开关感应到夜晚时,打开光照灯;当光电开关感应到白天时,关闭光照灯。

启航KS_IoT智能开发套件案例及代码之二

光电开关监测软件实现

代码目录:

applications\sample\wifi-iot\app\issdemo
|—iss_photosensitive
|—iss_photosensitive.c
|—iss_photosensitive.h

初始化GPIO

int32_t IssInitPhotoSensitive(void)
{
int32_t state = HI_ERR_FAILURE;
state = hi_io_set_func(PHOTOSENSITIVE_GPIO_NAME, PHOTOSENSITIVE_GPIO_FUNC);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "PHOTOSENSITIVE_GPIO_NAME IoSetFunc error");
state = IoTGpioSetDir(PHOTOSENSITIVE_GPIO_IDX, HI_GPIO_DIR_IN);
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "PHOTOSENSITIVE_GPIO_NAME IoTGpioSetDir error");
return HI_ERR_SUCCESS;
}

获取光电开关数据

int32_t IssReadPhotoSensitive(BoardEnvInfoValue *envInfo)
{
int32_t state = HI_ERR_FAILURE;
IotGpioValue value = HI_GPIO_VALUE0;
state = IoTGpioGetInputVal(PHOTOSENSITIVE_GPIO_IDX, &value);
if (state != HI_ERR_SUCCESS) {
envInfo->photoSensitive = -1;
}
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "PHOTOSENSITIVE_GPIO_NAME IoTGpioSetDir error");
envInfo->photoSensitive = value;
return state;
}

可燃气体监测实现

可燃气体监测原理

通过ADC接口实时采集当前环境可燃气体浓度,超过阈值时蜂鸣器会发出警报。

可燃气体监测硬件接口

MQ-4

启航KS_IoT智能开发套件案例及代码之二

特殊说明:

使用该功能,需要按下SW1按键,此时该功能才有效。

启航KS_IoT智能开发套件案例及代码之二

引脚连接说明:

ADC —– GPIO11

可燃气体监测功能中,GPIO10引脚配置设置见4.8章节

用跳线帽连接下图原理图中紫色方框位置

启航KS_IoT智能开发套件案例及代码之二

Rs 为传感器当前阻值,R0 为洁净空气中的值,ppm为可燃气体浓度。三者之间的关系为:

① Rs/R0 = 11.5428ppm^(-0.6549) 。由上图的电路图可得出

② (Vc – V2)/Rs = V2/R2。 Vc = 5V, V2 位 R25 电阻电压, 即 ADC 采集到的电压, R25= 1k。在空气洁净时测出电压为 0.25V 左右。故 R0 = 19K。

通过公式①,②可以推导出电压 V2 与 ppm 值的关系为:

ppm = pow(11.542819* V2/(5- V2),1.0/0.6549);

函数 pow 为计算 x 的 y 次方,x, y 均为 double 类型。

可燃气体监测软件实现

读取ADC电压数值,将电压值转换为可燃气体数值。

代码目录:

applications\sample\wifi-iot\app\issdemo
|—iss_combustible_gas
|—iss_combustible_gas.c
|—iss_combustible_gas.h

可燃气体数据转换和获取

int32_t IssGasAdcRead(BoardEnvInfoValue *envInfo)
{
int32_t state = HI_ERR_FAILURE;
uint16_t data = 0;
float voltage;
uint32_t gas;
state = hi_adc_read(HI_ADC_CHANNEL_5, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0xFF);
if (state != HI_ERR_SUCCESS) {
envInfo->gasVal.voltageVal = -1;
envInfo->gasVal.gasPpmVal = -1;
}
RUNTIME_ERR_RET_FAIL(state != HI_ERR_SUCCESS, "adc channel5 read failure.");
voltage = hi_adc_convert_to_voltage(data);
gas = pow(11.54 * 19 * voltage / (5 - voltage), 1.0 / 0.65);
envInfo->gasVal.voltageVal = voltage;
envInfo->gasVal.gasPpmVal = gas;
return state;
}

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://harmonyos.51cto.com​

启航KS_IoT智能开发套件案例及代码之二

© 版权声明

相关文章