资讯专栏INFORMATION COLUMN

科技不总是冷冰冰,智能便携打印机让文字更有温度!——嵌入式功能实现篇

Mr_houzi / 686人阅读

摘要:将信号拉高激活打印元件,接着使步进电机转动两步完成一点行的打印。步进电机的步长为,一点行的宽度为,因此打印出一点行的数据需要步进电机转两步。由于步进电机和热敏头不能长时间连续工作,因此打印份数不宜设置过多,否则容易烧坏电机和热敏头。

简介:利用Wi-Fi&BLE云模组让普通打印机实现App端输入文字即可实时&远程打印。

1、功能需求

基本打印流程:
(1)用户通过涂鸦App完成设备配网。
(2)将需要打印的文字或者简单图片输入文本框。
(3)输入完成后APP将文本框中的内容全部转换成bmp单色位图存储到云端,并将图片的url给到App。
(4)分别将第一段url和第二段url下发到设备,设备端将url拼接。
(5)设置打印份数后点击开始打印。
(6)设备收到打印命令后访问url,下载图片到模组后开始打印。
(7)返回打印结果(成功/失败)。

功能名称功能详解
打印份数设置具体要打印的份数,默认一份
生成第一段链接APP生成的图片会存储到云端,以url形式给到设备,url长度超过255个字节,由于IoT平台string类型DP最多只能容纳255个字节,因此需要两个DP
生成第二段链接将得到的两组url拼接成完整的url,设备访问该url将图片下载到模组
开始打印设置好打印份数,下发打印命令,设备开始打印
正在打印份数根据设置的打印份数,设备会上报当前正在打印的份数在APP显示
缺纸报警检测到打印机无纸时无法打印,并上报缺纸状态到APP
电量显示电量以10%间隔显示在APP
低电量报警电量在低于10%时APP电量报警
打印结果
打印状态打印成功、打印失败(缺纸、电池电量不足、图片拉去失败)

2、环境搭建

(1)开发环境搭建可以参考Wi-Fi 模组二次开发教程——1. SoC开发环境搭建。如果已经有虚拟机和乌班图的开发环境可直接跳至4.2 下载编译依赖工具处进行剩余环境搭建。
(2)产品创建可以参考Wi-Fi模组二次开发教程——2. 涂鸦IoT平台介绍。由于IoT平台品类中没有打印机,所以选择找不到品类?。默认自定义方案,填入产品名称和产品型号,通讯协议默认Wi-Fi&蓝牙,创建产品后添加所需的功能点。

功能点定义完成后选择设备面板为自由配置面板,其他步骤均可参考Wi-Fi模组二次开发教程——2. 涂鸦IoT平台介绍完成产品创建。
(3)参考Wi-Fi模组二次开发课程——3. 快速上手来完成代码修改编译、固件上传、获取token、烧录授权和设备配网。

3、功能实现

3.1 打印功能

打印是打印机最重要的功能点,其他所有的功能点都是在此基础上实现的。通过步进电机和热敏头的协同工作来实现字符和图片的打印。
打印头与涂鸦Wi-Fi&BLE双模模组之间通过SPI进行数据通信,具体打印步骤为:
(1)模组每次向热敏头发送48位数据。
(2)热敏头接收到数据后在CLK信号的上升沿将数据传输到移位寄存器。
(3)一行(48位)数据传输完成后将/LAT信号拉低紧接着拉高把数据存储到锁存寄存器中。
(4)将DST信号拉高激活打印元件,接着使步进电机转动两步完成一点行的打印。
(5)在电机转过两步后要及时将DST信号拉低,长时间加热会损坏加热元件甚至冒烟。

步进电机的步长为0.01325mm,一点行的宽度为0.0625mm,因此打印出一点行的数据需要步进电机转两步。DST信号激活频率为步进电机每转两步激活一次。
打印时序图如下:

步进电机时序图如下:

打印功能部示例代码:

/*** @function:set_motor_phases* @brief: set motor phases* @param[in]: phase[4]* @return: none*/STATIC VOID set_motor_phases(CONST UINT8_T phase[4]){    tuya_gpio_write(PH1, phase[0]);    tuya_gpio_write(PH2, phase[1]);    tuya_gpio_write(PH3, phase[2]);    tuya_gpio_write(PH4, phase[3]);}/*** @function:idle_motor* @brief: idel status no power consumption* @param[in]: none* @return: none*/VOID idle_motor(VOID){    if (isIdle) {        return;    }    CONST UINT8_T idle_phase[] = {0, 0, 0, 0};    set_motor_phases(idle_phase);    isIdle = TRUE;}/*** @function:set_motor_step* @brief: * @param[in]: none* @return: none*/VOID set_motor_step(VOID) {    isIdle = false;    CONST INT_T totalSteps = ARRAY_SIZE;    currStep = (currStep + totalSteps + 1) % totalSteps;    set_motor_phases(motor_phases[currStep]);}/*** @function:tuya_motor_feedPaper_line* @brief: Feed paper for `count` lines* @param[in]: count -> print line num* @param[in]: direction: FORWARD->forward  BACKWARD->backward* @param[in]: speed: Adjust the motor speed unit:ms* @return: none*/VOID tuya_motor_feedPaper_line(UINT_T count, INT8_T direction, UINT8_T speed){	INT_T i;	/* out of paper or cuont num is 0 return */	if (1 == tuya_TmlHead_out_of_paper_alarm() || 0 == count) {		return;	}	CONST UINT_T stepsPerLine = ARRAY_SIZE / 2;	for (i = 0; i < (stepsPerLine * count); i++) {		tuya_motor_set_motor_step(direction);		tuya_hal_system_sleep(speed);	// delay 2ms unit:ms	}}/*** @function:begin_print_line* @brief: send 1bpp data to printhead and begin heating* @param[in]: data -> The data to be printed* @return: none*/STATIC VOID begin_print_line(UINT8_T* data){	if (1 == out_of_paper_alarm()) {		return;	}	bk_spi_master_dma_send(&g_spi_msg);	tuya_hal_system_sleep(5);	tuya_gpio_write(PRINT_DST, FALSE);	tuya_gpio_write(PRINT_LAT, FALSE);	tuya_gpio_write(PRINT_LAT, TRUE);	tuya_gpio_write(PRINT_DST, TRUE);}/*** @function:end_printLine* @brief:end heating * @param[in]: none* @return: none*/STATIC VOID end_printLine(VOID){	tuya_gpio_write(PRINT_DST, FALSE);}/*** @function: print_1bLine* @brief: Print one line of data* @param[in]: data -> Data to be printed* @return: none*/STATIC VOID print_1bLine(UINT8_T* data){	if (1 == out_of_paper_alarm()) {		return;	}	begin_print_line(data);	motor_feedPaper_line(1, FORWARD, 2);    // The actual number of steps is 2*Param	end_printLine();	}

要合理控制步进电机送纸速度,速度过快容易走不动纸,速度过慢加热头会对热敏纸同一个点长时间加热使热敏纸颜色由黑变灰甚至变白,影响打印效果。

3.2 打印份数

打印份数默认打印一份,在APP上设置参数可调整打印份数。由于步进电机和热敏头不能长时间连续工作,因此打印份数不宜设置过多,否则容易烧坏电机和热敏头。

3.3 生成第一段链接 & 生成第二段链接

由于平台受限,url长度超过255个字节,string类型DP最多只能容纳255个字节,因此需要两个DP。url在代码中本质为字符串。APP将两端url下发到设备后再将得到的两组url拼接成完整的url,设备访问该url将图片下载到模组。

        case PRINT_NUM_DPID:            bmp_info.paper_num = root->value.dp_value;        break;        case CREATE_LINK1_DPID:            memset (bmp_info.first_url, 0, 255);            memcpy(bmp_info.first_url, root->value.dp_str, strlen(root->value.dp_str));        break;        case CREATE_LINK2_DPID:            memset (bmp_info.second_url, 0, 255);            memcpy(bmp_info.second_url, root->value.dp_str, strlen(root->value.dp_str));        break;

3.4 开始打印 & 正在打印的份数

设备收到打印命令后访问url下载图片到模组后开始打印。由于模组RAM有限,剩余空间只有40k左右,而需要打印的图片很可能超过了40k,因此采用一边拉取部分图片一边打印的方式完成打印。打印份数bmp_info.paper_num控制for循环的次数,bmp_info.print_num即为当前正在打印的份数,将print_num实时上报到APP即可显示当前正在打印的份数。
开始打印部分代码:

    CHAR_T *image_url = (CHAR_T *)malloc(512*sizeof(CHAR_T));    strcpy(image_url, "https://storage-proxy.tuyacn.com:7779/dst=");    tuya_hal_semaphore_wait(pv_handle);    strcat(image_url, bmp_info.first_url);    strcat(image_url, bmp_info.second_url);    for (bmp_info.print_num = 0; bmp_info.print_num < bmp_info.paper_num; bmp_info.print_num++) {        iot_httpc_download_file(image_url, PULL_SIZE, iot_download_image_cb, NULL, bmp_info.total_len, file_hmac);         tuya_bmp_print_num_update(++bmp_info.print_num);    }

3.5 缺纸报警

打印机内部采用一个反射性光电通断侦测传感器,当缺纸时,光电侦测发出的光无法被反射,输出高电平。当纸张正常,光电侦测发出的光被反射,由接收管接收,输出低电平。将输出的电平值实时上报到APP。当缺纸时,不能启动加热头和电机。
缺纸检测部分代码:

/** * @function: out_of_paper_alarm * @brief: detection printer have paper * @param: none * @return: ALARM-->out of paper  NORMAL-->have a paper * @others: none */UCHAR_T out_of_paper_alarm(VOID){    if (NO_PAPER == tuya_gpio_read(PAPER_SENSOR)) {		return PAPER_ALARM;    } else {		return PAPER_NORMAL;	}}	dp_arr[2].dpid = OUT_OF_PAPER_DPID;     dp_arr[2].type = PROP_BOOL;         dp_arr[2].time_stamp = 0;    dp_arr[2].value.dp_bool = out_of_paper_alarm();

3.6 电量显示 & 低电量报警

打印机采用7.4v可充电锂电池供电,采用ADC采集电池端的电压,显示10%、20%、…、90%、100%电量值,当电池电压等于10%时上报APP,并且红灯亮起,提醒用户充电。大于10%时绿灯常亮。该任务放在多带带的线程中每3s采集一次电池电压,并上报电量值。


ADC_ELECTRICITY处分压后电压为2.1v。
部分示例代码:

/*** @function:tuya_BatMon_BatStatus* @brief: Battery level display* @param[in]: none* @return: none*/VOID tuya_BatMon_BatStatus(VOID){    UINT16_T battery_val = 0;    BOOL_T bat_alarm = 0;    while (1) {        battery_val = tuya_BatMon_BatVal_get(2400, 4096, 4, 400);        if (battery_val <= precent_10) {            bat_alarm = 1;            tuya_BatMon_ch443k_toggle(BAT_LED_PIN, FALSE);            tuya_gpio_write(BAT_LED_PIN, FALSE);        } else {            bat_alarm = 0;            tuya_BatMon_ch443k_toggle(BAT_LED_PIN, TRUE);            tuya_gpio_write(BAT_LED_PIN, TRUE);        }        if (battery_val >= precent_100) {            vlotage_percent = _100p;        } else if (battery_val < precent_100 && battery_val >= precent_90) {            vlotage_percent = _90p;        } else if (battery_val < precent_90 && battery_val >= precent_80) {            vlotage_percent = _80p;        } else if (battery_val < precent_80 && battery_val >= precent_70) {            vlotage_percent = _70p;        } else if (battery_val < precent_70 && battery_val >= precent_60) {            vlotage_percent = _60p;        } else if (battery_val < precent_60 && battery_val >= precent_50) {            vlotage_percent = _50p;        } else if (battery_val < precent_50 && battery_val >= precent_40) {            vlotage_percent = _40p;        } else if (battery_val < precent_40 && battery_val >= precent_30) {            vlotage_percent = _30p;        } else if (battery_val < precent_30 && battery_val >= precent_20) {            vlotage_percent = _20p;        } else {            vlotage_percent = _10p;        }                /* Voltage detection frequency */        tuya_hal_system_sleep(CKECK_TIME);        tuya_update_Bat_Val_dp(bat_alarm);    }}

e if (battery_val < precent_50 && battery_val >= precent_40) {
vlotage_percent = _40p;
} else if (battery_val < precent_40 && battery_val >= precent_30) {
vlotage_percent = _30p;
} else if (battery_val < precent_30 && battery_val >= precent_20) {
vlotage_percent = _20p;
} else {
vlotage_percent = _10p;
}

    /* Voltage detection frequency */    tuya_hal_system_sleep(CKECK_TIME);    tuya_update_Bat_Val_dp(bat_alarm);} }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/119772.html

相关文章

  • 输入9V-12V输出8.4V1.5A双节锂电池充电芯片

    摘要:输入输出,非常适用于消费类电子产品,如便携式个人媒体播放器和便携式系统,为确保对高容量锂离子电池的可靠充电,这些全集成充电管理控制器在一个单芯片上集成了一些关键的标准充电管理和安全功能。 输入9V-12V输出8.4V1.5A双节锂电池充电芯片平板电脑MID 智能MID 便捷式MID 1A-1...

    不知名网友 评论0 收藏0
  • 谷歌董事长:我可以非常直接地说,互联网将消失

    摘要:当互联网概念在中国资本市场上方兴未艾之时,互联网巨头谷歌公司的执行董事长埃里克施密特在前段时间举行的座谈会上大胆预言互联网即将消失,一个高度个性化互动化的有趣世界物联网即将诞生。他说我可以非常直接地说,互联网将消失。 当互联网概念在中国资本市场上方兴未艾之时,互联网巨头谷歌公司的执行董事长埃里克•施密特在前段时间举行的座谈会上大胆预言:互联网即将消失,一个高度个性化、互动化的有趣世界——物联...

    hiyayiji 评论0 收藏0
  • 最新最全AI快报:马斯克被怼,谷歌最近太平...

    摘要:马斯克呼吁对人工智能进行监管,并警告说这种技术可能会造成独裁者并引发第三次世界大战。,谷歌最近并不太平。目前,双方正在联合承办的比赛。 AI行业动态 1,新浪美股讯,北京时间5月28日晚间,据外媒消息,IBM沃森和云高级副总裁大卫肯尼表示,人工智能已经证明是有益的。特斯拉首席执行官马斯克等发出的末日警告有些言过其实。它使网络变得更加安全,帮助医生护士和病人更好地找到医疗保健方式,帮助人...

    Astrian 评论0 收藏0
  • 亚马逊新时代:云服务独领风骚,AI助手无处

    摘要:亚马逊人工智能语音助手技能超过万个,全球各主要硬件厂商纷纷搭载或兼容,使得其亚马逊助手无处不在。物联网设备透过云端实现跨行业和跨设备互联互通,所收集数据除了在边缘侧处理,还需要上传至云端,云端作为数据集散地,各种数据经过云端AI处理后,对这些数据利用将会带来新的商业模式。在物联网资深专家杨剑勇看来,云计算是全球物联网重要基础设施,作为物联网产业发展基石,聚集了亚马逊、微软、谷歌和BAT等重量...

    Bmob 评论0 收藏0
  • 蚂蚁微贷互动营销技术体系实践

    摘要:财富管理专场上,蚂蚁金服微贷事业群高级前端技术专家王卓做了主题为蚂蚁微贷互动营销技术体系实践的精彩分享。通过互动技术,最终实现拉新,留存和促活等目标。营销技术方案对接研发平台,通过凤蝶系统和研发管理体系进行打通。 摘要:以数字金融新原力(The New Force of Digital Finance)为主题,蚂蚁金服ATEC城市峰会于2019年1月4日上海如期举办。财富管理专场上,蚂...

    aristark 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<