启航KS_IoT智能开发套件案例及代码之二
https://harmonyos.51cto.com
案例简介
启航KS包括1块核心板和4块扩展板,本文档包括以下功能案例:
启航KS核心板实现的案例
- OLED显示
- 温湿度监测
- 超声波测距
- 人体红外感应
- 电机控制
- 蜂鸣器
- 光照强度监测
- 按键功能
- RGB呼吸灯
- NFC
- Wi-Fi
- 光电开关监测
- 可燃气体监测
启航KS扩展板实现的案例
- PM2.5监测
- 甲醛监测
- BDS/GPS定位
- 姿态监测
启航KS核心板功能实现
核心板功能区分布图如下:
RGB呼吸灯功能实现
RGB呼吸灯功能原理
RGB呼吸灯功能是通过循环控制PWM占空比,调节LED亮度,实现RGB呼吸灯效果。
RGB呼吸灯硬件接口
RGB
按键控制使用的GPIO接口为GPIO10, GPIO11, GPIO12。其引脚连接说明如下:
- RED —– GPIO12
- BLUE —– GPIO10
- GREEN —– GPIO11
RGB呼吸灯功能中,GPIO10、GPIO11、GPIO12引脚配置设置见4.6章节
用跳线帽连接下图原理图中紫色方框位置
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
NFC采用I2C协议进行数据通信。使用的GPIO 引脚分别是 GPIO13,GPIO14,其引脚连接说明如下:
- SDA —– GPIO13
- SCL —– GPIO14
用跳线帽连接下图原理图中紫色方框位置
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
引脚连接说明如下:
光敏传感器使用的GPIO接口为GPIO06
用跳线帽连接下图原理图中紫色方框位置
额外功能说明:
光电开关联动光照灯D6,需要按下SW1。当光电开关感应到夜晚时,打开光照灯;当光电开关感应到白天时,关闭光照灯。
光电开关监测软件实现
代码目录:
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
特殊说明:
使用该功能,需要按下SW1按键,此时该功能才有效。
引脚连接说明:
ADC —– GPIO11
可燃气体监测功能中,GPIO10引脚配置设置见4.8章节
用跳线帽连接下图原理图中紫色方框位置
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;
}