# 智能语音垃圾桶——设备端 搭建好开发环境后,就可以开始编写代码 #### 一、设备功能代码 ##### 1、初始化设备 (1)智能语音垃圾桶需要四个舵机,所以我们需要对GPIO6、GPIO7、GPIO9、GPIO10做初始化设置pwm功能 ```c void SmartdustbinInit(void) { GpioInitOperation(HAL_WIFI_IOT_IO_NAME_GPIO_10, 0, IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0); GpioInitOperation(HAL_WIFI_IOT_IO_NAME_GPIO_9, 0, IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0); GpioInitOperation(HAL_WIFI_IOT_IO_NAME_GPIO_7, 0, IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0); GpioInitOperation(HAL_WIFI_IOT_IO_NAME_GPIO_6, 0, IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0); } ``` ##### 2、舵机功能 可将GPIO10、GPIO9、GPIO7、GPIO6分别用作可回收垃圾、不可回收垃圾、厨余垃圾、其他垃圾的开关功能 ###### (1)设置舵机旋转角度及方向 ```c //舵机正转 void set_engine_angle_R(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_10, IOT_GPIO_VALUE1); hal_udelay(duty - i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_10, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - (duty - i*THE_PARM_OF_CACL_CYCLE)); } } void set_engine_angle_U(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE1); hal_udelay(duty - i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - (duty - i*THE_PARM_OF_CACL_CYCLE)); } } void set_engine_angle_K(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_7, IOT_GPIO_VALUE1); hal_udelay(duty - i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_7, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - (duty - i*THE_PARM_OF_CACL_CYCLE)); } } void set_engine_angle_O(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_6, IOT_GPIO_VALUE1); hal_udelay(duty - i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_6, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - (duty - i*THE_PARM_OF_CACL_CYCLE)); } } //舵机反转 void set_engine_angle_reversal(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_10, IOT_GPIO_VALUE1); hal_udelay(i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_10, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - i*THE_PARM_OF_CACL_CYCLE); } } void set_engine_angle_reversal_U(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE1); hal_udelay(i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_9, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - i*THE_PARM_OF_CACL_CYCLE); } } void set_engine_angle_reversal_K(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_7, IOT_GPIO_VALUE1); hal_udelay(i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_7, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - i*THE_PARM_OF_CACL_CYCLE); } } void set_engine_angle_reversal_O(hi_s32 duty) { uint32 count = duty/THE_PARM_OF_CACL_CYCLE; for (int i = 1; i <= count; i++) { IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_6, IOT_GPIO_VALUE1); hal_udelay(i*THE_PARM_OF_CACL_CYCLE); IoTGpioSetOutputVal(HAL_WIFI_IOT_IO_NAME_GPIO_6, IOT_GPIO_VALUE0); hal_udelay(THE_CYCLES_OF_PWM_CONTROL - i*THE_PARM_OF_CACL_CYCLE); } } ``` ##### 3、写dustbin_open()和dustbin_close()函数方便调用 ```c void Dustbin_close_R(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:close_R", 1); set_engine_angle_reversal(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = FALSE; } void Dustbin_close_U(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:close_U", 1); set_engine_angle_reversal_U(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = FALSE; } void Dustbin_close_K(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:close_K", 1); set_engine_angle_reversal_K(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = FALSE; } void Dustbin_close_O(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:close_O", 1); set_engine_angle_reversal_O(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = FALSE; } void Dustbin_open_R(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:open_R ", 1); set_engine_angle_R(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = TRUE; } void Dustbin_open_U(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:open_U ", 1); set_engine_angle_U(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = TRUE; } void Dustbin_open_K(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:open_K ", 1); set_engine_angle_K(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = TRUE; } void Dustbin_open_O(void) { OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, " ", 1); OledShowStr(0, Y_SHOW_SMART_CAN_SHOW_OPEN, "Dustbin:open_O ", 1); set_engine_angle_O(THE_ANGLE_OF_dustbin_WROK); g_dustbinIsOpen = TRUE; } ``` #### 二、容量上报 我们需要一个包含四个垃圾桶容量上报的函数,上报属性可参考profile文件 ```c int IotProfile_Report_ALL(int dev_status,int recyclables_Capacity,int unrecyclable_Capacity,int kitchenGarbage_Capacity,int otherRubbish_Capacity) { int ret = -1; cJSON *root; char *jsonString; IotProfileService service; IotProfileKV kvDev_status;//dev IotProfileKV kvRecyclables_Capacity;//可回收垃圾桶 IotProfileKV kvUnrecyclable_Capacity;//不可回收垃圾桶 IotProfileKV kvKitchenGarbage_Capacity;//厨余垃圾垃圾桶 IotProfileKV kvOtherRubbish_Capacity;//其他垃圾 /* package the data */ service.eventTime = NULL; service.serviceID = "SmartDustbin_DATA"; service.propertyLst = &kvDev_status; service.nxt = NULL; kvDev_status.key = "Dev_Status"; kvDev_status.value = &dev_status; kvDev_status.type = IOT_PROFILE_KEY_DATATYPE_INT; kvDev_status.nxt = &kvRecyclables_Capacity; kvRecyclables_Capacity.key = "Recyclables_Capacity"; kvRecyclables_Capacity.value = &recyclables_Capacity; kvRecyclables_Capacity.type = IOT_PROFILE_KEY_DATATYPE_INT; kvRecyclables_Capacity.nxt = &kvUnrecyclable_Capacity; kvUnrecyclable_Capacity.key = "Unrecyclable_Capacity"; kvUnrecyclable_Capacity.value = &unrecyclable_Capacity; kvUnrecyclable_Capacity.type = IOT_PROFILE_KEY_DATATYPE_INT; kvUnrecyclable_Capacity.nxt = &kvKitchenGarbage_Capacity; kvKitchenGarbage_Capacity.key = "KitchenGarbage_Capacity"; kvKitchenGarbage_Capacity.value = &kitchenGarbage_Capacity; kvKitchenGarbage_Capacity.type = IOT_PROFILE_KEY_DATATYPE_INT; kvKitchenGarbage_Capacity.nxt = &kvOtherRubbish_Capacity; kvOtherRubbish_Capacity.key = "OtherRubbish_Capacity"; kvOtherRubbish_Capacity.value = &otherRubbish_Capacity; kvOtherRubbish_Capacity.type = IOT_PROFILE_KEY_DATATYPE_INT; kvOtherRubbish_Capacity.nxt = NULL; jsonString = IoTProfilePackage(&service); if ( NULL != jsonString) { ret = CLOUD_ReportMsg(jsonString); free(jsonString); } else { RaiseLog(LOG_LEVEL_ERR, "format the report message error"); } return ret; } ``` #### 三、接收及解析iot云命令 ##### 1、首先需要一个云端命令处理函数 ```c int CLOUD_CommandCallBack(const char *jsonString) { cJSON *objRoot = NULL; cJSON *objCmdName = NULL; int ret = -1; if (jsonString == NULL) { return ret; } if ((objRoot = cJSON_Parse(jsonString)) == NULL) { RaiseLog(LOG_LEVEL_ERR, "could not parse the payload\r\n"); goto EXIT_JSONPARSE; } if ((objCmdName = cJSON_GetObjectItem(objRoot, "command_name")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "%s:could not get the cmd name from json\r\n"); goto EXIT_CMDOBJ; } if (0 == strcmp(cJSON_GetStringValue(objCmdName), "Open_R")) { ret = DealMain_dustbinOpenRecyclables(objRoot); } else if(0 == strcmp(cJSON_GetStringValue(objCmdName), "Open_U")) { ret = DealMain_dustbinOpenUnrecyclable(objRoot); } else if(0 == strcmp(cJSON_GetStringValue(objCmdName), "Open_K")) { ret = DealMain_dustbinOpenKitchenGarbage(objRoot); }else if(0 == strcmp(cJSON_GetStringValue(objCmdName), "Open_O")) { ret = DealMain_dustbinOpenOtherRubbish(objRoot); }else { RaiseLog(LOG_LEVEL_ERR, "unresolved command:%d\r\n", cJSON_GetStringValue(objCmdName)); } EXIT_CMDOBJ: EXIT_JSONPARSE: if (objRoot != NULL) { cJSON_Delete(objRoot); } return ret; } ``` ##### 2、对命令进行解析处理,IoT云下发Open_R命令将会调用DealMain_dustbinOpenRecyclables() ```c static int DealMain_dustbinOpenRecyclables(cJSON *objCmd)//云端命令处理 { int ret = -1; cJSON *objParas = NULL; cJSON *objPara = NULL; CommandParamSetOpen setOpen; if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json"); return ret; } if (Getcommand_dustbinOpenRecyclables(&setOpen, objParas) < 0) { RaiseLog(LOG_LEVEL_ERR, "GetCommandSetOpen failed!\n"); } ret = IotProfile_CommandCallback(CLOUD_COMMAND_SETOPEN, &setOpen); return ret; } ``` ##### 3、对IoT云命令进行响应回馈 ```c int IotProfile_CommandCallback(int command, void *buf) { CommandParamSetOpen setOpen; CLOUD_CommandType cmd = (CLOUD_CommandType)command; if (cmd == CLOUD_COMMAND_SETOPEN) { setOpen = *(CommandParamSetOpen *)buf; g_appController.recyclables_Capacity = setOpen.openStatus; return 0; } return -1; } ``` ##### 4、对Open命令的命令参数进行进一步解析 ```c static int Getcommand_dustbinOpenRecyclables(CommandParamSetOpen *setOpen,cJSON *objCmd) { cJSON *objPara = NULL; if (setOpen== NULL || objCmd == NULL) { RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n"); return -1; } memset(setOpen, 0x00, sizeof(CommandParamSetOpen)); if ((objPara = cJSON_GetObjectItem(objCmd, "OpenRecyclables")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json"); return -1; } if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) { Dustbin_open_R(); } else { Dustbin_close_R(); } return 0; } static int Getcommand_dustbinOpenUnrecyclable(CommandParamSetOpen *setOpen,cJSON *objCmd) { cJSON *objPara = NULL; if (setOpen== NULL || objCmd == NULL) { RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n"); return -1; } memset(setOpen, 0x00, sizeof(CommandParamSetOpen)); if ((objPara = cJSON_GetObjectItem(objCmd, "OpenUnrecyclable")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json"); return -1; } if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) { Dustbin_open_U(); } else { Dustbin_close_U(); } return 0; } static int Getcommand_dustbinOpenKitchenGarbage(CommandParamSetOpen *setOpen,cJSON *objCmd) { cJSON *objPara = NULL; if (setOpen== NULL || objCmd == NULL) { RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n"); return -1; } memset(setOpen, 0x00, sizeof(CommandParamSetOpen)); if ((objPara = cJSON_GetObjectItem(objCmd, "OpenKitchenGarbage")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json"); return -1; } if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) { Dustbin_open_K(); } else { Dustbin_close_K(); } return 0; } static int Getcommand_dustbinOpenOtherRubbish(CommandParamSetOpen *setOpen,cJSON *objCmd) { cJSON *objPara = NULL; if (setOpen== NULL || objCmd == NULL) { RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n"); return -1; } memset(setOpen, 0x00, sizeof(CommandParamSetOpen)); if ((objPara = cJSON_GetObjectItem(objCmd, "OpenOtherRubbish")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json"); return -1; } if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) { Dustbin_open_O(); } else { Dustbin_close_O(); } return 0; } ``` #### 四、hi3861获取语音开发板命令 语音开发板识别一级命令:“你好,垃圾桶”成功后,说出第二级控制命令后,通过UART串口协议输出cJson包:Open_R、Open_U、Open_K、Open_O,需要hi3861对接口进行监听,以保证不会漏掉语音命令 ##### 1、hi3861初始化GPIO0和GPIO1用于UART串口协议传输 ```c void UartInit(void){ RaiseLog(LOG_LEVEL_INFO,"[2022012x01] entry into UartInit"); IoTGpioInit(HAL_WIFI_IOT_IO_NAME_GPIO_0); HalIoSetFunc(HAL_WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_UART1_TXD); IoTGpioInit(HAL_WIFI_IOT_IO_NAME_GPIO_1); HalIoSetFunc(HAL_WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_UART1_RXD); hi_uart_attribute uart_attr = { .baud_rate = UART_BAUD_RATE, /* baud_rate: 9600 */ .data_bits = UART_DATA_BITS, /* data_bits: 8bits */ .stop_bits = UART_STOP_BITS, .parity = 0, }; RaiseLog(LOG_LEVEL_INFO,"[2022012x01] uart_init success"); /* Initialize uart driver */ hi_u32 ret = hi_uart_init(HI_UART_IDX_1, &uart_attr, HI_NULL); if (ret != HI_ERR_SUCCESS) { printf("[220214x02]Failed to init uart! Err code = %d\n", ret); return; } } ``` ##### 2、对UART串口程序创建线程 ``` static void *uart_demo_task(void) { static uint16_t countSendTimes = 0; static uint8_t countReceiveTimes = 0; g_uartController.isReadBusy = false; printf("[Initialize uart successfully\n"); while (1) { osDelay(50); UartReceiveMessage();//Collecting Serial Port Data hi_sleep(SMART_CAN_SLEEP_2500MS); } return 0; } void uart_task_create(void) { RaiseLog(LOG_LEVEL_INFO,"uart_task_create"); osThreadAttr_t attr; attr.name = "uartTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = UART_DEMO_TASK_STAK_SIZE; attr.priority = CONFIG_TASK_UART_PRIOR; if (osThreadNew((osThreadFunc_t)uart_demo_task, NULL, &attr) == NULL) { printf("[220214x02]Falied to create uart_demo_task!\n"); } } ``` ##### 3、串口数据收集程序 ```c static void UartReceiveMessage(void) { char *recData; printf("----Listening----"); RaiseLog(LOG_LEVEL_INFO,"Start Listening serial port"); if (UartIsBufEmpty()) { return; } if (g_uartController.isReadBusy) { return; } g_uartController.isReadBusy = true; g_ReceivedDatalen = hi_uart_read(DEMO_UART_NUM, g_uart_buff, UART_BUFF_SIZE); if (g_ReceivedDatalen > 0) { printf("UartReceiveMessage rcvData len:%d,msg:%s.\n", g_ReceivedDatalen, g_uart_buff); setVoiceCommand();//Setting voice Commands memset(g_uart_buff, 0, sizeof(g_uart_buff)); g_ReceivedDatalen = 0; } g_uartController.isReadBusy = false; } ``` ##### 4、语音命令解析程序 ```c static void setVoiceCommand(void) { if (strstr(g_uart_buff, "Open_R") != NULL) { printf("[220214x02]listened Open_R\n"); Dustbin_open_R(); printf("[220214x02] Delay 10s close_R\n"); osDelay(1000); Dustbin_close_R(); }else if (strstr(g_uart_buff, "Open_U") != NULL) { printf("[220214x02]listened Open_U\n"); Dustbin_open_U(); printf("[220214x02] Delay 10s close_U\n"); osDelay(1000); Dustbin_close_U(); }else if (strstr(g_uart_buff, "Open_K") != NULL) { printf("[220214x02]listened Open_K\n"); Dustbin_open_K(); printf("[220214x02] Delay 10s close_K\n"); osDelay(1000); Dustbin_close_K(); }else if (strstr(g_uart_buff, "Open_O") != NULL) { printf("[220214x02]listened Open_O\n"); Dustbin_open_O(); printf("[220214x02] Delay 10s close_O\n"); osDelay(1000); Dustbin_close_O(); } } ```