极具创意的自动售货机设计方案推荐

更新时间Invalid date

概况

技术发明一直在改变人们的生活方式。自动售货机便是其中之一,在不需要工作人员或人工协助的情况下,它可以 24 小时向客户分发产品。整个售货过程都由机器自动完成,使人们在购买物品和交易方面更加便利。

使用涂鸦 LZ201 CAT1 模组,借助涂鸦 MCU SDK 低代码开发方式,开发者可以跟随本教程在涂鸦 IoT 平台上快速开发一款自动售货机产品原型。

物料清单

硬件 (8)软件 (2)
  • 74HC165

    数量:1

    八位并行输入,串行输出的移位寄存器,用于检测电机转动位置情况查看详情

  • 74HC595

    数量:2

    八位串行输入、并行输出的移位寄存器,用于提供输出各个电机的控制信号查看详情

  • FDS9945

    数量:10

    N 沟道 MOS 管,用于驱动电机查看详情

  • FDS9958

    数量:10

    P 沟道 MOS 管,用于驱动电机查看详情

  • LZ201-CN

    数量:1

    涂鸦 LZ201-CN Cat.1 模组,用于售货机和云平台的信息交互查看详情

  • STM32

    数量:1

    主控芯片,控制售货机正常工作查看详情

  • Motor

    数量:10

    减速电机,控制物品掉落

  • ST-LINK

    数量:1

    用于 STM32 微控制器的调试和编程。查看详情

步骤

  • 第 1 步:硬件设计

    整体硬件由供电单元、主控单元、电机驱控控制单元、电机到位检测单元、无线通讯单元和其他外设单元组成。具体如下图所示:
    frame

    供电单元

    本款自动售货机主要包含以下几个部件的供电:

    • 主电源:需要输入 24V 直流电作为主电源。该 24V 直流电可以直接接 MOS 管作为售货机中电机的输入电源。
    • 无线通信单元:供电电压为 4V,可以使用 LM2576 这款 DC-DC 稳压芯片将 24V 转换成 4V。LM2576 最大可驱动 3A 的负载,有优异的线性和负载调整能力,完全满足无线通信单元的需求。
    • 主控单元芯片:一般供电电压为 3.3V,可以采用 S-1206B33-U3T1G 这款 LDO 芯片将 4V 电压降到 3.3V。

    主控单元

    该单元采用 STM32F103RET6 作为主控芯片。该芯片是一款基于 ARM 架构的高密度性能 32 位微处理器,主频最大可支持 72MHZ,多达 11 个定时器,内部集成了复位电路、低电压检测、调压器和精确的 RC 振荡器电路。更多关于该芯片的信息,请参考 STM32F103RE 芯片介绍;更多关于该芯片的数据规格,请参考 STM32F103RE 数据规格书

    STM32

    电机驱动控制单元

    控制单元组成
    该单元采用 74HC595 (74HC595 数据规格书)八位串行输入、并行输出的移位寄存器用于提供输出各个电机的控制信号。
    74HC595

    每个电机的两端各接一个 FDS9945 N 沟道 MOS 管(FDS9945 数据规格书)和一个 FDS9958 P 沟道 MOS 管(FDS9958 数据规格书),其中

    • FDS9958 的源极接 24V,栅极接信号线,漏极接电机的正极。
      FDS9958
    • FDS9945 的源极接 GND,栅极接信号线,漏极接电机的负极。
      FDS9945
      当 FDS9945 和 FDS9958 两个 MOS 管同时导通的时候,电机便可转动。

    组件数量

    • 信号线:需要 11 条。本款自动售货机总共有 10 个货道,需采用 10 个电机,理论上总共需要 20 条信号线。为了节约资源,可以将所有电机的负极连接到同一个 FDS9945 的漏极,这样可以将信号线减少至 11 条。
    • 芯片:需要 2 颗串联。一颗 74HC595 只支持 8 位串入并出,为了满足 11 位数据需求,可以将两颗 74HC595 串联,这样最多可支持 16 位信号数据。

    电机到位检测单元

    该单元采用 74HC165 (74HC165 数据规格书)八位并行输入,串行输出的移位寄存器用于检测电机转动位置情况。
    74HC165

    当电机转动到一定位置时,到位开关输出低电平信号给 74HC165 并行输入脚。主控单元读取 74HC165 串行输出脚,检测到某一位低电平时,将对应位的电机停转,避免多次掉落物品。

    由于 I/O 口资源有限,开发者可以让 10 个电机共用一个到位开关。

    无线通信单元

    该单元主要用于售货机和云平台的信息交互,可以采用涂鸦 LZ201-CN CAT1 模组。这是由涂鸦智能开发的一款 LTE Cat.1 蜂窝网络模组。关于该模组的数据规格,请参考 LZ201-CN CAT1 模组规格书

    LZ201

    模组主要由一个高集成度的 LTE Cat.1 芯片 UIS8910DM 及其外围电路构成,其中:

    • 内置了 LTE Cat.1 网络通信协议栈和丰富的库函数。
    • 内嵌了 Cortex A5 应用处理器和 Cat.1bis 调制解调器。
    • 集成了 64MB Flash,128 MB SRAM。
    • 支持 USB、UART、SDIO、SPI、I2C、I2S 和 ADC 等接口。
    • 支持显示屏、摄像头、键盘矩阵、麦克风、喇叭、充电、MicroSD 卡和 USIM 卡等外设。

    开发者只需要通过移植涂鸦 MCU SDK,即可以实现对 App、云、售货机三者的通信控制。当然,这部分也可以用 WB3S Wi-Fi 模组或者其他通信模组来代替。

    其他外设单元

    该单元的外设,可以根据开发者自身需求自行设计添加,比如

    • 增加网络指示灯,用于表示当前网络状态。
    • 增加电源指示灯,用于表示当前电源状态。
    • 增加温度传感器,用于检测售货机内部温度。
    • 增加掉落检测装置,用于检测物品是否确实掉落,形成反馈。
    • 增加多路按键,用于需要实现某种特定的按键功能。
    • 增加 RS-485 通信接口,用于售货机与其他 RS-485 设备通信,增强联动性。
    • 增加液晶显示单元,用于人机交互。

    完成以上硬件的设计后,可以根据结构尺寸,设计对应的 PCB,并且完成焊接,测试等工作。下图为参考示例:
    PCB

  • 第 2 步:在涂鸦 IoT 平台上创建产品

    1. 登录 涂鸦IoT平台,单击 创建产品

    2. 标准类目 导航栏中,选择 户外出行 > 智能电动车
      选择品类

    3. 选择 自定义方案 中的 智能电动车 方案。

    4. 输入产品名称,产品型号(可选),选择通信协议为 LTE Cat1,并单击 创建产品
      智能电动车

    5. 在功能定义选项中,根据自身需要选择功能。
      标准功能

    6. (可选)若标准功能中缺少您需要的功能,可在 自定义功能 区域单击 添加功能,根据实际需求进行配置。
      例如,本次可以添加两个 DP 点,一个用于指示平台下发的数据,一个用于指示自动售货机上报的数据。
      自定义功能

    7. 设备面板 页签中选择想要的面板,开始调试时可选择开发调试面板,后面可根据自身需要自由配置面板。
      设备面板

    8. 硬件开发 页签中,选择 涂鸦标准模组MCU SDK开发,并选择 LZ201-CN LTE Cat.1模组
      硬件开发

    9. 上述操作完成之后,单击 下载全部 下载所有开发需要用到的资料,开始嵌入式程序的开发。

  • 第 3 步:嵌入式开发

    开发者在获取了 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 把程序下载到开发板中。

  • 第 4 步:操作演示

    打开涂鸦智能 App,在 Item 输入栏中输入 XXYYZZZZZZZZ,其中

    • XX 表示第 X 个货道;
    • YY表示货道上剩余的物品数量;
    • ZZZZZZZZ 为订单号(可以为任意值)。

    如,输入0104aabbccdd,表示第 1 个货道剩余 4 个物品,订单号为 aabbccdd。

    数据发送成功后,可以看到电机开始转动,当物品掉落后,电机停止转动。

    注意:当前货道的物品剩余量务必要和输入物品号相同,比如第 1 个货道有4个物品时,只有输入 0104 才会有效,输入 0105 或 0103 等其他值,电机都是不会转动的。

    App 操作

小结

涂鸦物联网开发平台为开发者提供了便捷的 IoT 开发工具与服务,助力开发者更高效的完成设备接入,并为开发者提供物联网应用开发及场景服务能力。