风扇由于便捷、易安装、能耗低的特性,在消费品市场非但没有受空调的影响,反而新增了远程控制、自然风、暖风、清凉风、睡眠风、负离子功能等新型产品,甚至还有驱蚊、低噪风扇,具有非常高的实用价值。
随着消费者对健康的日益关注,产品设计还可以在提高空气质量、便携移动、低噪声等方向进行新品研发。
本教程主要介绍目前市场上流行 直流变频风扇 的设计思路,通过方案设计、硬件设计、涂鸦 IoT 平台 DP 设置、嵌入式开发,来讲解普通风扇智能化的研发流程。如果你也感兴趣,可以一起动手操作,制作出一款原型产品,了解物联网硬件产品的设备端开发。
硬件设计思路如下:
相比传统交流电机风扇,无刷直流电机(BLDC,Brushless DC electric motor)具有中低速转矩性能好等多种优势,且使用寿命更长。因此直流电机选用的是 MINEBEA 12V 直流三相无刷电机,作为风量控制电机。
驱动器主要控制直流无刷电动机(Brushless DC electric motor,BLDC)。采用峰岹的 BLDC 解决方案,采用 FU6832 作为 BLDC 的控制 MCU。该芯片有双核 8051 内核 + ME,16KB Flash,256 bytes IRAM, 768 bytes XRAM SSOP24 封装,集成 BLDC 控制算法。
模组的选择影响到智能硬件的无线通信方式。其中,Wi-Fi 作为常见的通信方式,也是居家或者商业运用较广的方案,因此采用涂鸦 SoC 方案的 CBU Wi-Fi 模组作为通信模组。查看详情
作为风量调节旋钮,顺时针调大,逆时针调小,该编码器可根据要求,设置需要的档位数。该器件手柄支持360°选择,结构上无限位点。
至少 8 个指示灯,由 Wi-Fi 模组的 I/O 口控制。
用于电源、定时、按键、Wi-Fi 配网重置、风扇工作模式的按键。
输出 12V DC/2A,用于满足风扇整体供电要求。
转换市电然后用于 Wi-Fi 模组及外围供电、FU6832S 电机驱动控制芯片及外围供电。
有关风量控制电机、电机驱动器等器件的选型,请参考上文物料清单。本小节继续介绍相关器件的其他信息,方便您了解细节逻辑:
电机驱动器 芯片 I/O 口:
旋钮编码器(风量调节):
编码器的脉冲波形:
编码器的外围电路:
按键设计:方案设计 4 个按键,按键均设置为低电平有效,按键功能:
电源按键:开启关闭风扇。
定时按键:设置风扇定时开关的时间段。
Wi-Fi 配网重置按键:清除已联网的 Wi-Fi 的网络信息,恢复到出厂设置状态。
模式按键:设置风扇工作模式。模式按键设置在编码器上。
指示灯设计:方案设计 8 个指示灯,指示灯由 CBU Wi-Fi 模组的 I/O 口控制,设置均为低电平点亮,指示灯功能:
4 个档位指示灯
3 个模式指示灯
1 个网络状态指示灯
增加一个指示灯亮度调节控制 I/O 口,可设置调节 LED 指示灯亮度
交互信号:采用 PWM 信号作为 Wi-Fi 模组和 FU6832S 电机驱动控制芯片的交互信号。
电源方案:电源选用绿源电源插头,输出 12V DC/2A,用于满足风扇整体供电要求。
转换电路:此次教程需要一个 12V DC 转 3.3V DC 的转换电路,用于 Wi-Fi 模组及外围供电。一个 12V DC 转 5V DC 的转换电路,用于 FU6832S 电机驱动控制芯片及外围供电。
转换电路采用基于矽力杰的 SY8121B 芯片的降压(Buck)电路。SY8121B 是一款高效,响应速度快的同步整流方案的 DC-DC 转换芯片。
Wi-Fi 模组及外围电路接线:
DC-DC 转换电路接线:
FU6832S 电机控制芯片及外围电路:
功能设计 | 详细说明 |
---|---|
工作模式 | 正常风 自然风:忽大忽小间隔 15 秒 睡眠风:每隔一小时自动降档,最后降到最低档 |
风速控制 | 编码器旋转控制风扇,顺时针旋转风速 +,逆时针旋转风速 - |
模式切换 | 编码器按钮短按切换模式,长按设备复位 |
本地定时 | 定时结束后自动关机,定时按键:无定时 -> 1 小时 -> 2 小时 -> 3 小时 -> 4 小时 -> 无定时。 |
指示灯显示 1 | 4 颗指示灯显示风速,4 颗指示灯指示 8 档风速,闪烁代表 1 档,常亮代表 2 档。4 颗指示灯还复用本地定时指示。 |
指示灯显示 2 | LED 有 8 颗,除指示风速 4 颗 LED 外,还有 4 颗指示灯。一颗 Wi-Fi 指示灯,指示 Wi-Fi 状态;其他三颗指示当前风扇模式。 |
电源 | 电源按键,控制风扇的启动和断电状态 |
设备配网 | 长按 Wi-Fi 按键,设备进入配网模式 |
指示灯调节 | LED 指示灯亮度可通过 App 调整,正常亮度,较暗亮度 |
断电记忆 | 设备通电自动恢复 |
电机驱动板和电压转换板:
Wi-Fi 模组控制板:
进入 涂鸦 IoT 平台的产品创建页面。
创建一款风扇产品,创建产品时,选择 小家电 > 风扇,开发方案确认为 自定义方案,通讯方式选择为 Wi-Fi。
设置 DP 时,需要考虑您想要添加的风扇功能,与嵌入式开发的功能设置做一一映射。
选择面板后,就进入硬件开发阶段,此时选择 涂鸦标准模组SDK开发 作为云端连接方式,并选择 CBU 模组为通信模组。
更多详情和步骤说明,请参考 Wi-Fi 模组 SDK 开发参考。
相关代码仓库:
根据本节进行代码开发和代码编译后,您需要将生成的固件上传,填入具体信息。详情请参考 固件升级。
调用该函数 tuya_iot_wf_gw_unactive()
以进入配网模式,涂鸦模组 SDK 对于网络状态的定义有以下几种:
typedef BYTE_T GW_WIFI_NW_STAT_E;
长按进入配网模式功能实现:
STATIC VOID wifi_key_process(TY_GPIO_PORT_E port,PUSH_KEY_TYPE_E type,INT_T cnt)
{
PR_DEBUG("port:%d,type:%d,cnt:%d",port,type,cnt);
OPERATE_RET op_ret = OPRT_OK;
UCHAR_T ucConnectMode = 0;
if (port = WIFI_KEY_PIN) {
if (LONG_KEY == type) { //press long enter linking network
PR_NOTICE("key long press");
/* 手动移除设备 */
tuya_iot_wf_gw_unactive();
} else if (NORMAL_KEY == type) {
PR_NOTICE("key normal press");
} else {
PR_NOTICE("key type is no deal");
}
}
return;
}
STATIC VOID wifi_config_init(VOID)
{
OPERATE_RET op_ret = OPRT_OK;
/* LED 相关初始化 */
tuya_gpio_inout_set(WIFI_LED_PIN, FALSE);
tuya_set_led_light_type(wifi_led_handle, OL_HIGH, 0, 0); //关闭 LED
/* LED 相关初始化 */
op_ret = tuya_create_led_handle(WIFI_LED_PIN, TRUE, &wifi_led_handle);
if (op_ret != OPRT_OK) {
PR_ERR("key_init err:%d", op_ret);
return;
}
tuya_set_led_light_type(wifi_led_handle, OL_HIGH, 0, 0);
/* 按键相关初始化 */
KEY_USER_DEF_S key_def;
op_ret = key_init(NULL, 0, WIFI_KEY_TIMER_MS);
if (op_ret != OPRT_OK) {
PR_ERR("key_init err:%d", op_ret);
return;
}
/* 初始化 key 相关参数 */
memset(&key_def, 0, SIZEOF(key_def));
key_def.port = WIFI_KEY_PIN; //按键引脚
key_def.long_key_time = WIFI_KEY_LONG_PRESS_MS; //长按时间配置
key_def.low_level_detect = WIFI_KEY_LOW_LEVEL_ENABLE; //TRUE:低电平算按下,FALSE:高电平算按下
key_def.lp_tp = LP_ONCE_TRIG; //
key_def.call_back = wifi_key_process; //按键按下后回调函数
key_def.seq_key_detect_time = WIFI_KEY_SEQ_PRESS_MS; //连按间隔时间配置
/* 注册按键 */
op_ret = reg_proc_key(&key_def);
if (op_ret != OPRT_OK) {
PR_ERR("reg_proc_key err:%d", op_ret);
}
return;
}
Wi-Fi 状态提示:
STATIC VOID wifi_state_led_reminder(IN CONST GW_WIFI_NW_STAT_E cur_stat)
{
switch (cur_stat)
{
case STAT_LOW_POWER: //wifi 连接超时,进入低功耗模式
tuya_set_led_light_type(wifi_led_handle, OL_HIGH, 0, 0); //关闭提示灯
break;
case STAT_UNPROVISION: //SamrtConfig 配网模式,等待连接
tuya_set_led_light_type(wifi_led_handle, OL_FLASH_HIGH, WIFI_LED_FAST_FLASH_MS, 0xffff); //LED 快闪
break;
case STAT_AP_STA_UNCFG: //ap 配网模式,等待连接
tuya_set_led_light_type(wifi_led_handle, OL_FLASH_HIGH, WIFI_LED_LOW_FLASH_MS, 0xffff); //LED 慢闪
break;
case STAT_AP_STA_DISC:
case STAT_STA_DISC: //SamrtConfig/ap 正在连接中
tuya_set_led_light_type(wifi_led_handle, OL_HIGH, 0, 0); //关闭 LED
break;
case STAT_CLOUD_CONN:
case STAT_AP_CLOUD_CONN: //连接到涂鸦 IoT
tuya_set_led_light_type(wifi_led_handle, OL_LOW, 0, 0); //LED 常亮
break;
default:
break;
}
}
常见的风扇都会有相关的工作模式,最简单的就是控制风量,从弱到强。除此之外,我们还可以根据生活场景来设计设备的模式,例如普通、自然风、睡眠风三种工作模式,然后通过 PWM 对 BLDC 进行控制。
风扇的控制函数:
VOID_T fan_speed_set(UINT_T speed)
{
UINT_T fan_speed_pwm_duty_cycle = 0;
if (speed <= 0) {
vSocPwmSetDuty(BLDC_PWM_ID, (BLDC_PWM_FAN_OFF));
return;
}
//由于电机在30%以下工作时间过长会出现异常,这里对 PWM 输出进行一些处理,使输出的 PWM 在 30%-99% 之间
fan_speed_pwm_duty_cycle = (UINT_T)(BLDC_PWM_FAN_MIN + ((BLDC_PWM_FAN_MAX - BLDC_PWM_FAN_MIN) * (speed / 100.0)));
vSocPwmSetDuty(BLDC_PWM_ID, (fan_speed_pwm_duty_cycle));
return;
}
普通工作模式:
static VOID_T fan_mode_normal(VOID_T)
{
INT_T opRet = LIGHT_OK;
//关闭睡眠模式的定时器,防止干扰普通模式的运行
opRet = opSocSWTimerStop(SLEEP_MODE_TIMER);
if (opRet != LIGHT_OK) {
PR_ERR("stop sleep timer error");
}
//关闭自然模式的定时器,防止干扰普通模式的运行
opRet = opSocSWTimerStop(NATURAL_MODE_TIMER);
if (opRet != LIGHT_OK) {
PR_ERR("stop natural timer error");
}
fan_speed_set(fan_state.speed);
PR_NOTICE("+++ normal mode fan_state.speed : %d", fan_state.speed);
}
自然风工作模式:
static VOID_T fan_mode_natural_timer_cb(VOID_T)
{
//如果关机,不执行任何操作
if (fan_state.on_off == FALSE) {
opSocSWTimerStop(NATURAL_MODE_TIMER);
return;
}
if (natural_speed_low_flag) {
PR_NOTICE("natural mode low speed");
fan_speed_set(1);
} else {
PR_NOTICE("natural mode high speed");
fan_speed_set(fan_state.speed);
}
natural_speed_low_flag = ~(natural_speed_low_flag);
opSocSWTimerStart(NATURAL_MODE_TIMER, NATURAL_SPEED_CHANGE_TIME * 1000, fan_mode_natural_timer_cb);
}
static VOID_T fan_mode_natural(VOID_T)
{
INT_T opRet = LIGHT_OK;
//关闭睡眠模式的定时器,防止干扰自然模式的运行
opRet = opSocSWTimerStop(SLEEP_MODE_TIMER);
if (opRet != LIGHT_OK) {
PR_ERR("stop sleep timer error");
}
natural_speed_low_flag = ~(0x00);
fan_speed_set(fan_state.speed);
opSocSWTimerStart(NATURAL_MODE_TIMER, NATURAL_SPEED_CHANGE_TIME * 1000, fan_mode_natural_timer_cb);
}
睡眠风工作模式:
static VOID_T fan_sleep_mode_task(VOID_T)
{
UINT8_T cur_gear;
PR_NOTICE("enter fan_sleep_mode_task!");
//判断当前是不是最低档。若为最低档,不再降速
if (fan_state.speed <= g_fan_speed_gear[0]) {
fan_speed_set(g_fan_speed_gear[0]);
change_fan_state();
opSocSWTimerStop(SLEEP_MODE_TIMER);
return;
}
cur_gear = get_cur_gear();
PR_NOTICE("current gear is %d.", cur_gear);
fan_state.speed = g_fan_speed_gear[--cur_gear];
//改变档位转速
fan_speed_set(fan_state.speed);
fan_speed_led_set(get_cur_gear()+1);
PR_NOTICE("speed change to %d.", fan_state.speed);
//写入风扇状态到Flash中
write_flash_fan_state();
//启动睡眠模式,1h 减一档
opSocSWTimerStart(SLEEP_MODE_TIMER, SLEEP_SPEED_CHANGE_TIME * 1000, fan_sleep_mode_task);
}
static VOID_T fan_mode_sleep(VOID_T)
{
UINT8_T cur_gear;
INT_T opRet = LIGHT_OK;
SHORT_T i;
//关闭自然模式的定时器,防止干扰睡眠模式的运行
opRet = opSocSWTimerStop(NATURAL_MODE_TIMER);
if (opRet != LIGHT_OK) {
PR_ERR("stop sleep timer error");
}
opRet = opSocSWTimerStop(SLEEP_MODE_TIMER);
if (opRet != LIGHT_OK) {
PR_ERR("stop sleep timer error");
}
//判断当前档位
cur_gear = get_cur_gear();
fan_state.speed = g_fan_speed_gear[cur_gear];
//改变档位转速
fan_speed_set(fan_state.speed);
PR_NOTICE("speed change to %d.", fan_state.speed);
//写入风扇状态到Flash中
write_flash_fan_state();
opSocSWTimerStart(SLEEP_MODE_TIMER, SLEEP_SPEED_CHANGE_TIME * 1000, fan_sleep_mode_task);
}
按键初始化:
VOID_T fan_key_init(VOID_T)
{
OPERATE_RET opRet;
tuya_gpio_inout_set(KEY_ROTARY_A, TRUE);
tuya_gpio_inout_set(KEY_ROTARY_B, TRUE);
/* 旋钮正反转检测初始化 */
BkGpioEnableIRQ(KEY_ROTARY_A, IRQ_TRIGGER_FALLING_EDGE, knod_key_cb, NULL);
opRet = key_init(NULL, 0, 0);
if (opRet != OPRT_OK) {
PR_ERR("key_init err:%d", opRet);
return;
}
memset(&KEY_DEF_T, 0, SIZEOF(KEY_DEF_T));
KEY_DEF_T.port = KEY_ROTARY_N;
KEY_DEF_T.long_key_time = 3000;
KEY_DEF_T.low_level_detect = TRUE;
KEY_DEF_T.lp_tp = LP_ONCE_TRIG;
KEY_DEF_T.call_back = key_press_cb;
KEY_DEF_T.seq_key_detect_time = 400;
opRet = reg_proc_key(&KEY_DEF_T);
if (opRet != OPRT_OK) {
PR_ERR("reg_proc_key err:%d", opRet);
return;
}
KEY_DEF_T.port = KEY_TIMER;
opRet = reg_proc_key(&KEY_DEF_T);
if (opRet != OPRT_OK) {
PR_ERR("reg_proc_key err:%d", opRet);
return;
}
KEY_DEF_T.port = KEY_POWER;
KEY_DEF_T.long_key_time = 10000;
opRet = reg_proc_key(&KEY_DEF_T);
if (opRet != OPRT_OK) {
PR_ERR("reg_proc_key err:%d", opRet);
return;
}
}
按键功能回调函数:
编码器回调函数,编码器功能的功能实现,简单的使用的外部中断触发后,开始判断 A 和 B 引脚电平是否相同来确认是顺时针旋转还是逆时针旋转。
STATIC VOID_T knod_key_cb(VOID_T)
{
INT8_T current_gear;
//如果关机,不执行任何操作
if (fan_state.on_off == FALSE) {
return;
}
BkGpioFinalize(KEY_ROTARY_A);
//得到当前档位
current_gear = get_cur_gear();
if(tuya_gpio_read(KEY_ROTARY_A) != tuya_gpio_read(KEY_ROTARY_B)) {
PR_DEBUG("A != B"); //顺时针方向
current_gear++;
if (current_gear > (MAX_GEAR_NUMBER-1)) {
current_gear = (MAX_GEAR_NUMBER-1);
}
fan_state.speed = g_fan_speed_gear[current_gear];
} else {
PR_DEBUG("A == B"); //逆时针方向
current_gear--;
if (current_gear < 0) {
current_gear = 0;
}
fan_state.speed = g_fan_speed_gear[current_gear];
}
/* 改变风扇状态:风速,模式,LED */
change_fan_state();
write_flash_fan_state();
PR_DEBUG("fan current_gear is : %d", current_gear);
/* 旋钮正反转检测初始化 */
BkGpioEnableIRQ(KEY_ROTARY_A, IRQ_TRIGGER_FALLING_EDGE, knod_key_cb, NULL);
}
其他普通按键回调函数:
STATIC VOID_T key_press_cb(TY_GPIO_PORT_E port,PUSH_KEY_TYPE_E type,INT_T cnt)
{
PR_DEBUG("port: %d, type: %d, cnt: %d", port, type, cnt);
/* 旋钮按键 */
if (port == KEY_ROTARY_N) {
if (fan_state.on_off == FALSE) {
return;
}
switch (type) {
case NORMAL_KEY:
PR_DEBUG("knod press.");
if (fan_state.mode == NORMAL_MODE) {
fan_state.mode = NATURAL_MODE;
} else if (fan_state.mode == NATURAL_MODE) {
fan_state.mode =SLEEP_MODE;
} else {
fan_state.mode = NORMAL_MODE;
}
change_fan_state();
break;
case LONG_KEY:
PR_DEBUG("knod long press.");
/* 复位,删除所有用户信息,恢复到默认模式 */
fan_state = fan_default_state;
change_fan_state();
write_flash_fan_state();
break;
case SEQ_KEY:
PR_DEBUG("knod SEQ press, the count is %d.", cnt);
break;
default:
break;
}
}
/* 定时按键 */
if (port == KEY_TIMER) {
if (fan_state.on_off == FALSE) {
return;
}
switch (type) {
case NORMAL_KEY:
PR_DEBUG("timer press.");
if (fan_state.local_timing == 0xFF) {
fan_state.local_timing = 1;
} else if (fan_state.local_timing >= 4) {
fan_state.local_timing = 0xFF; //取消定时
} else {
fan_state.local_timing++;
}
fan_local_timing_shutdown();
break;
case LONG_KEY:
PR_DEBUG("timer long press.");
break;
case SEQ_KEY:
PR_DEBUG("timer SEQ press, the count is %d.", cnt);
break;
default:
break;
}
}
/* 开关按键 */
if (port == KEY_POWER) {
switch (type) {
case NORMAL_KEY:
if (fan_state.on_off == FALSE) {
fan_state.on_off = TRUE;
PR_DEBUG("Turn on");
} else {
fan_state.on_off = FALSE;
PR_DEBUG("Turn off");
}
change_fan_state();
break;
case LONG_KEY:
PR_DEBUG("power long press.");
break;
case SEQ_KEY:
PR_DEBUG("power SEQ press, the count is %d.", cnt);
break;
default:
break;
}
}
write_flash_fan_state();
}
定时功能是基础的控制功能,对持续工作的设备有重要作用,尤其是风扇、空调、香薰机等设备。
本地定时功能简单的调用了一个软件定时器来实现:
VOID_T fan_timing_cd(VOID_T)
{
fan_state.local_timing--;
opSocSWTimerStop(SHUTDOWN_TIMER);
if (fan_state.local_timing == 0 || fan_state.on_off == FALSE) {
fan_turn_off();
} else {
PR_NOTICE("fan_state.local_timing ======== %d", fan_state.local_timing);
write_flash_fan_state();
opSocSWTimerStart(SHUTDOWN_TIMER, (SINGLE_TIMING*1000), fan_timing_cd);
fan_local_timing_led_set(fan_state.local_timing);
}
}
VOID_T fan_local_timing_shutdown(VOID_T)
{
fan_local_timing_led_set(fan_state.local_timing);
if (fan_state.local_timing > 4) { //无定时
opSocSWTimerStop(SHUTDOWN_TIMER);
return;
}
PR_NOTICE("run shutdown timer");
opSocSWTimerStop(SHUTDOWN_TIMER);
opSocSWTimerStart(SHUTDOWN_TIMER, (SINGLE_TIMING*1000), fan_timing_cd);
}
自动恢复又称断电记忆,是指在设备断电并重新通电后,可以重新以之前的状态继续工作,无需人为干扰。
该功能依赖于 Flash,每次改变状态后,都将当前设备信息存储到 Flash 中。在设备通电后,首先读取 Flash 中的数据对设备状态进行设定。
VOID_T read_flash_fan_state(VOID_T)
{
INT_T opRet, i;
UCHAR_T fan_state_data_crc;
UCHAR_T before_fan_power_off_state[FAN_STATE_STORAGE_LEN]; //断电前风扇状态
opRet = uiSocFlashRead(SAVE_TYP1, FAN_STATE_OFFSET, FAN_STATE_STORAGE_LEN*SIZEOF(UCHAR_T), before_fan_power_off_state);
if (opRet != FAN_STATE_STORAGE_LEN) {
PR_ERR("read data error for Flash");
return;
}
//判断头部数据是否正确
if (before_fan_power_off_state[0] != FAN_DATA_HEAD) {
PR_ERR("data head error");
return;
}
fan_state_data_crc = get_crc_8(before_fan_power_off_state, (FAN_STATE_STORAGE_LEN - 1)*SIZEOF(UCHAR_T));
//校验数据是否正确
if (fan_state_data_crc != before_fan_power_off_state[FAN_STATE_STORAGE_LEN - 1]) {
PR_ERR("crc error, before_fan_power_off_state[%d] = %02x, crc data = %02x.", FAN_STATE_STORAGE_LEN - 1, before_fan_power_off_state[FAN_STATE_STORAGE_LEN - 1], fan_state_data_crc);
return;
}
//将从 Flash 读取到的数据,存放到结构体中
fan_state.on_off = before_fan_power_off_state[FLASH_FAN_STATE_ON_OFF];
fan_state.mode = before_fan_power_off_state[FLASH_FAN_STATE_MODE];
fan_state.speed = before_fan_power_off_state[FLASH_FAN_STATE_SPEED];
fan_state.local_timing = before_fan_power_off_state[FLASH_FAN_STATE_TIMING];
return;
}
VOID_T write_flash_fan_state(VOID_T)
{
INT_T opRet, i;
UCHAR_T fan_state_buffer[FAN_STATE_STORAGE_LEN];
fan_state_buffer[0] = FAN_DATA_HEAD;
fan_state_buffer[1] = fan_state.on_off;
fan_state_buffer[2] = fan_state.mode;
fan_state_buffer[3] = fan_state.speed;
fan_state_buffer[4] = fan_state.local_timing;
fan_state_buffer[5] = get_crc_8(fan_state_buffer, (FAN_STATE_STORAGE_LEN - 1)*SIZEOF(UCHAR_T));
for (i=0; i<FAN_STATE_STORAGE_LEN; i++) {
PR_NOTICE(" +++ fan_state_buffer is [%d] : %02x", i, fan_state_buffer[i]);
}
opRet = opSocFlashWrite(SAVE_TYP1, FAN_STATE_OFFSET, fan_state_buffer, FAN_STATE_STORAGE_LEN * SIZEOF(UCHAR_T));
if (opRet != LIGHT_OK) {
PR_ERR("write Flash error");
}
return;
}
设备恢复初始设置又称复位功能。该功能可以通过将 Flash 中存储的设备状态更改为初始化值,或者直接擦除 Flash 中的信息来实现。
VOID_T erase_flash_fan_state(VOID_T)
{
INT_T opRet, i;
UCHAR_T fan_state_buffer[FAN_STATE_STORAGE_LEN];
fan_state.on_off = FALSE;
fan_state.mode = NORMAL_MODE;
fan_state.speed = 1;
fan_state_buffer[0] = FAN_DATA_HEAD;
fan_state_buffer[1] = FALSE; //fan_state.on_off
fan_state_buffer[2] = NORMAL_MODE; //fan_state.mode
fan_state_buffer[3] = 1; //fan_state.speed
fan_state_buffer[4] = 0xFF; // fan_state.local_timing
fan_state_buffer[5] = get_crc_8(fan_state_buffer, (FAN_STATE_STORAGE_LEN - 1)*SIZEOF(UCHAR_T));
for (i=0; i<FAN_STATE_STORAGE_LEN; i++) {
PR_NOTICE(" +++ fan_state_buffer is [%d] : %02x", i, fan_state_buffer[i]);
}
opRet = opSocFlashWrite(SAVE_TYP1, FAN_STATE_OFFSET, fan_state_buffer, FAN_STATE_STORAGE_LEN * SIZEOF(UCHAR_T));
if (opRet != LIGHT_OK) {
PR_ERR("write Flash error");
}
return;
}
当用户通过 App 改变风扇状态,例如从自然风模式切换成睡眠风模式,可以调用该函数实现,当然使用按键也可以控制设备。
VOID_T change_fan_state(VOID_T)
{
if (fan_state.on_off == FALSE) {
fan_turn_off();
hw_report_all_dp_status();
PR_NOTICE("stop sleep & natural timer");
return;
}
if (fan_state.bright == 1) {
fan_led_dimmer(100);
} else {
fan_led_dimmer(900);
}
if (fan_state.mode == SLEEP_MODE) {
PR_NOTICE("enter sleep mode");
fan_mode_sleep();
} else if (fan_state.mode == NATURAL_MODE) {
PR_NOTICE("enter natural mode");
fan_mode_natural();
} else {
PR_NOTICE("enter normal mode");
fan_mode_normal();
}
hw_report_all_dp_status();
/* speed LED set */
fan_speed_led_set(get_cur_gear()+1);
fan_mode_led_set();
return;
}
经过以上开发过程的风扇可以连接到 Wi-Fi 网络,实现远程控制。控制的方式可以是语音、遥控器、智能手机、微信小程序、平板电脑,或者您设计的物理按键。
您可以在 AppStore 等应用商店下载 涂鸦智能,通过扫码配网来实现设备远程控制,连接到涂鸦 IoT 云。
有关其他控制方式,请参考 App 开发。
在硬件设计阶段,为了方便您了解整体的操作流程,我们省略了大量的背景信息。您可以在本章节了解到更多细节,供您参考。
红色流向:电流从 AH 高位 MOS 流入电机的 MOT A,再从 MOT B 流出,经过 BL 低位 MOS 回到电源负端。
蓝色流向:电流从 BH 高位 MOS 流入电机的 MOT B,再从 MOT C 流出,经过 CL 低位 MOS 回到电源负端。
绿色流向:电流从 CH 高位 MOS 流入电机的 MOT C,再从 MOT A 流出,经过 AL 低位 MOS 回到电源负端。
FU6832S 芯片有 6 个指定引脚H_PU、H_PV、H_PW、L_U、L_V、L_W 用于控制三相直流无刷电机,内置上拉电阻和下拉电阻,高电平最大值是 VCC 电压。
只要将芯片供电的输入电压和电机工作电压保持相同,就不需要再在这些引脚的外围增加电平转换电路,可直接用三颗驱动芯片 AO4606 驱动电机的 U、V、W 三个引脚,该芯片由一个 Nmos 和 Pmos 组成,通过引脚走线可设计成半桥驱动电路。
FU6832S 芯片内置一个可配置增益的独立运算放大器,外围增加取样电阻,便可用于实现电机过流检测保护。
电机正反转监测电路,通过电阻分压后,进入 FU6832S 芯片 14、15、16 脚。
因为FU6832S芯片数字电路引脚的电平是5V,Wi-Fi模块的引脚电平是3.3V,因此两个通信间需要增加电平转换电路。
CBU 由一个高集成度的无线射频芯片 BK7231N 和少量外围器件构成,可以支持 AP 和 STA 双角色连接,并同时支持 BLE 连接,运行速度最高可到 120 MHz ,还内置2Mbyte 闪存和 256 KB RAM。它拥有的外设:PWM、UART、SPI;其中可配置6路的 32 位硬件 PWM ,非常适合高品质的 LED 控制。模组可用普通IO口有16个,也满足方案对IO口的需求。更多详情,请参考 CBU 模组规格书。