技术发明一直在改变人们的生活方式。自动售货机便是其中之一,在不需要工作人员或人工协助的情况下,它可以 24 小时向客户分发产品。整个售货过程都由机器自动完成,使人们在购买物品和交易方面更加便利。
使用涂鸦 LZ201 CAT1 模组,借助涂鸦 MCU SDK 低代码开发方式,开发者可以跟随本教程在涂鸦 IoT 平台上快速开发一款自动售货机产品原型。
整体硬件由供电单元、主控单元、电机驱控控制单元、电机到位检测单元、无线通讯单元和其他外设单元组成。具体如下图所示:
本款自动售货机主要包含以下几个部件的供电:
该单元采用 STM32F103RET6 作为主控芯片。该芯片是一款基于 ARM 架构的高密度性能 32 位微处理器,主频最大可支持 72MHZ,多达 11 个定时器,内部集成了复位电路、低电压检测、调压器和精确的 RC 振荡器电路。更多关于该芯片的信息,请参考 STM32F103RE 芯片介绍;更多关于该芯片的数据规格,请参考 STM32F103RE 数据规格书。
控制单元组成
该单元采用 74HC595 (74HC595 数据规格书)八位串行输入、并行输出的移位寄存器用于提供输出各个电机的控制信号。
每个电机的两端各接一个 FDS9945 N 沟道 MOS 管(FDS9945 数据规格书)和一个 FDS9958 P 沟道 MOS 管(FDS9958 数据规格书),其中
组件数量
该单元采用 74HC165 (74HC165 数据规格书)八位并行输入,串行输出的移位寄存器用于检测电机转动位置情况。
当电机转动到一定位置时,到位开关输出低电平信号给 74HC165 并行输入脚。主控单元读取 74HC165 串行输出脚,检测到某一位低电平时,将对应位的电机停转,避免多次掉落物品。
由于 I/O 口资源有限,开发者可以让 10 个电机共用一个到位开关。
无线通信单元
该单元主要用于售货机和云平台的信息交互,可以采用涂鸦 LZ201-CN CAT1 模组。这是由涂鸦智能开发的一款 LTE Cat.1 蜂窝网络模组。关于该模组的数据规格,请参考 LZ201-CN CAT1 模组规格书。
模组主要由一个高集成度的 LTE Cat.1 芯片 UIS8910DM 及其外围电路构成,其中:
开发者只需要通过移植涂鸦 MCU SDK,即可以实现对 App、云、售货机三者的通信控制。当然,这部分也可以用 WB3S Wi-Fi 模组或者其他通信模组来代替。
其他外设单元
该单元的外设,可以根据开发者自身需求自行设计添加,比如
完成以上硬件的设计后,可以根据结构尺寸,设计对应的 PCB,并且完成焊接,测试等工作。下图为参考示例:
登录 涂鸦IoT平台,单击 创建产品。
在 标准类目 导航栏中,选择 户外出行 > 智能电动车。
选择 自定义方案 中的 智能电动车 方案。
输入产品名称,产品型号(可选),选择通信协议为 LTE Cat1,并单击 创建产品。
在功能定义选项中,根据自身需要选择功能。
(可选)若标准功能中缺少您需要的功能,可在 自定义功能 区域单击 添加功能,根据实际需求进行配置。
例如,本次可以添加两个 DP 点,一个用于指示平台下发的数据,一个用于指示自动售货机上报的数据。
在 设备面板 页签中选择想要的面板,开始调试时可选择开发调试面板,后面可根据自身需要自由配置面板。
在 硬件开发 页签中,选择 涂鸦标准模组MCU SDK开发,并选择 LZ201-CN LTE Cat.1模组。
上述操作完成之后,单击 下载全部 下载所有开发需要用到的资料,开始嵌入式程序的开发。
开发者在获取了 MCU SDK 开发包之后,需要将 SDK 文件添加到自己的工程中,根据编译中的错误信息提示逐个修改。
由于 MCU 和选择的 PIN 脚不一定相同,以下为一些驱动程序,仅供参考。完整示例程序请参考 tuya-iotos-embeded-mcu-demo-4g-vending-machine。
串口配置
/***********************************************************
* Function: USART3_Init
* Input: uint32_t pclk2,uint32_t bound
* Output: none
* Return: none
* Notice: 串口初始化
***********************************************************/
void USART3_Init(uint32_t pclk2,uint32_t bound)
{
float temp;
uint16_t mantissa;
uint16_t fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<3; //使能PORTB口时钟
RCC->APB1ENR|=1<<18; //使能串口3时钟
GPIOB->CRH&=~(0xf<<8|0xf<<12);
GPIOB->CRH|=0X0B<<8|8<<12;//IO状态设置
GPIOB->ODR|=1<<11;
RCC->APB1RSTR|=1<<18; //复位串口3
RCC->APB1RSTR&=~(1<<18);//停止复位
//波特率设置
USART3->BRR=mantissa; // 波特率设置
USART3->CR1|=0X200C; //1位停止,无校验位.
USART3->CR1|=1<<8; //PE中断使能
USART3->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(1,2,USART3_IRQn,2);//组2
}
串口接收数据
/***********************************************************
* Function: USART3_IRQHandler
* Input: none
* Output: none
* Return: none
* Notice: 串口中断服务函数,接收一个字节数据
***********************************************************/
void USART3_IRQHandler(void)
{
if(USART3->SR&(1<<5))//接收到数据
{
uart_receive_input((unsigned char)(USART3->DR));
}
}
串口发送数据
/***********************************************************
* Function: Uart3_PutChar
* Input: uint8_t
* Output: none
* Return: uint8_t
* Notice: 发送一个字节数据,并返回发送是否超时的状态
***********************************************************/
uint8_t Uart3_PutChar(uint8_t data)
{
uint8_t ret=1;
uint16_t timeout=0x8000;
USART3->DR = data;
while((USART3->SR&1<<6)!=1<<6)//等待发送完毕
{
timeout--;
if( 0 == timeout )
{
ret = 1;
break;
}
}
if( 0 != timeout )
{
ret = 0;
}
return ret;
}
/**
* @brief 串口发送数据
* @param[in] {value} 串口要发送的1字节数据
* @return Null
*/
void uart_transmit_output(u8 value)
{
//#error "请将MCU串口发送函数填入该函数,并删除该行"
Uart3_PutChar(value);
/*
//Example:
extern void Uart_PutChar(u8 value);
Uart_PutChar(value); //串口发送函数
*/
}
读取 74HC165 数据
/***********************************************************
* Function: HC165In
* Input: none
* Output: none
* Return: uint8_t
* Notice: 读取 74HC165 的八个引脚状态,并返回对应的八位数据
***********************************************************/
uint8_t HC165In(void)
{
uint8_t i,dat=0;
CP_SET;
PL_RESET;
delay_us(10);
PL_SET;
delay_us(10);
for(i=0;i<8;i++)
{
dat=dat<<1;
if(ODATA==1)
{
dat=dat+1;
}
CP_RESET;
delay_us(10);
CP_SET;
delay_us(10);
}
CP_RESET;
return dat;
}
发送 74HC595 数据
本函数通过 74HC595 输出不同的电平信号给 N 沟道 MOS 管和 P 沟道 MOS 管,由此实现电机转动控制。
/***********************************************************
* Function: HC595Send
* Input: uint16_t
* Output: none
* Return: none
* Notice: 将 16 位的数据通过两个 74HC595 引脚输出
***********************************************************/
void HC595Send(uint16_t data)
{
uint8_t j;
LOCK_RESET;
delay_us(10);
for (j = 16; j > 0; j--)
{
SHIFT_RESET;
delay_us(10);
if(data & 0x8000)
{
INDATA_SET;
}
else
{
INDATA_RESET;
}
delay_us(10);
data <<= 1;
SHIFT_SET;
delay_us(10);
}
LOCK_SET;
delay_us(10);
}
例如,我们想让第 X 个(0≤X≤9)电机转动使物品掉落,只要调用
HC595Send(1<<X||1<<10);
其中 1<<X
表示给第 X 个 P 沟道 MOS 管高电平信号;1<<10
表示给 N 沟道 MOS 管高电平信号。
说明:由于电路中所有的 N 沟道 MOS 管共用了一个信号口,所以调用时固定为 1<<10。
同理,我们想让电机停止转动,只需要调用
HC595Send(0);
由于不同电路设计差异,函数中的实际参数会有所不同,需要根据实际硬件来处理。
下发的串口事件处理
下发数据的长度为 6 个字节,可以约定第 0 位为货道号,第 1 位为物品序号,后面 4 位为订单号。
开发者也可以根据自己的需要,规定通讯协议。以下程序,仅供参考。
/*****************************************************************************
函数名称 : dp_download_m_num_handle
功能描述 : 针对DPID_M_NUM的处理函数
输入参数 : value:数据源数据
: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 只下发类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_m_num_handle(const unsigned char value[], unsigned short length)
{
//示例:当前 DP 类型为 RAW
unsigned char ret;
const unsigned char error[6]={"ERROR1"};
/*
//RAW类型数据处理
*/
if((length==6)&&(value[0]<11)&&(value[1]<10))
{
IoT_receive[Q_U3.rear].data[0]=value[0];
IoT_receive[Q_U3.rear].data[1]=value[1];
IoT_receive[Q_U3.rear].data[2]=value[2];
IoT_receive[Q_U3.rear].data[3]=value[3];
IoT_receive[Q_U3.rear].data[4]=value[4];
IoT_receive[Q_U3.rear].data[5]=value[5];
F_TASK_MOTOR_OPEN++;
rear_inc(&Q_U3);
}
else
{
mcu_dp_raw_update(DPID_R_NUM,error,6);
}
//处理完 DP 数据后应有反馈
ret = mcu_dp_raw_update(DPID_M_NUM,value,length);
if(ret == SUCCESS)
return SUCCESS;
else
return ERROR;
}
编译与下载
程序编写完成之后,单击 Build 并根据软件提示修改相关错误或者警告信息。
待程序编译通过之后,就可以下载到开发板中进行调试和测试。
STM32 支持 ST-Link ,J-Link 等工具下载,这里推荐 ST-Link,引脚连接方式如下:
ST-Link | STM32F103 |
---|---|
SWCLK | SWCLK |
SWDIO | SWDIO |
NRST | NRST |
VDD | VDD |
GND | GND |
连接无误后,单击 Download 把程序下载到开发板中。
打开涂鸦智能 App,在 Item 输入栏中输入 XXYYZZZZZZZZ,其中
XX
表示第 X 个货道;YY
表示货道上剩余的物品数量;ZZZZZZZZ
为订单号(可以为任意值)。如,输入0104aabbccdd,表示第 1 个货道剩余 4 个物品,订单号为 aabbccdd。
数据发送成功后,可以看到电机开始转动,当物品掉落后,电机停止转动。
注意:当前货道的物品剩余量务必要和输入物品号相同,比如第 1 个货道有4个物品时,只有输入 0104 才会有效,输入 0105 或 0103 等其他值,电机都是不会转动的。
涂鸦物联网开发平台为开发者提供了便捷的 IoT 开发工具与服务,助力开发者更高效的完成设备接入,并为开发者提供物联网应用开发及场景服务能力。