摘要
自然语音作为人机交互在目前得以广泛的应用以及极大的发展前景。该设计介绍了基于非指定人语音芯片LD3320的语音控制器结构及其实现语音控制的方法。该语音控制器利用STM32F103C8T6单片机作为主要控制器,控制芯片对输入的进行语音识别并处理,根据语音指令产生相对应的脉冲序列,替代按键式遥控器,实现对电路的语音控制。本次设计采用了ICRPUTE公司的 LD3320语音识别芯片和相关控制电路,设计实现一款语音控制系统,该系统可以通过语音控制操作,同时按键也可以进行同时控制家用电器工作的功能。
关键词:LD3320;语音识别;STM32单片机
Abstract
As a human-computer interaction, natural speech has been widely used and has great development prospects. The design introduces the structure of voice controller based on non designated person voice chip ld3320 and the method of realizing voice control. The voice controller uses stm32f103c8t6 single chip microcomputer as the main controller. The control chip recognizes and processes the input voice, generates the corresponding pulse sequence according to the voice command, replaces the key remote controller, and realizes the voice control of the circuit. This design uses the ld3320 speech recognition chip and related control circuit of icrput company to design and implement a speech control system. The system can operate through speech control, and the key can also control the work of household appliances at the same time。
Key words: LD3320; Speech recognition; STM32 single chip microcompute.
目录
第一章 绪论
- 课题的背景
语音识别是人机交互通信的一种重要技术,20世纪60年代,计算机的应用推动了语音识别的发展。这时期的重要成果对于语音识别的发展产生了深远影响。 随着语音识别理论研究的深入和数字信号处理软,硬件技术的发展。语音识别技术应用的研究越来越受到人们的关注。智能语音家电控制系统实质上就是一个替代传统手动开关的收声控的电子开关。
语音识别作为人类与机器之间的沟通中很重要的环节,它的应用领域十分广阔。集成电路的迅速发展有利于将拥有多种功能的语音识别系统嵌入到芯片或模块上,使得语音识别这一技术在各个方面都得以利用,而嵌入式语音识别技术开发也会变得更有价值。
- 3 设计研究内容
本次毕业设计主要以STM32F103C8T6单片机和LD3320语音芯片为核心控制器件,对语音芯片LD3320外界的麦克风采集声音信号,在通过LD3320语音芯片进行频谱分析,在提取语音特征之后和关键词语列表中的关键词进行对比匹配,最后找出得分最高的关键词作为识别结果,输出给单片机,单片机进行处理后,在输出信号来控制继电器,或者灯,风扇,步进电机等外接设备,从而达到语音识别控制设备。
主要内容包括:
(1)语音可以正确识别对应的指令
(2)OLED可以正常显示数据
(3)可以正确读取DHT11温湿度传感器测量的数据
(5)WT588语音模块可以正确的播放语音
(6)步进电机驱动电路的设计
第二章 硬件设计
- 系统框架
硬件主要以STM32单片机以及LD3320语音识别模块为核心,通过软件和硬件的结合实现语音下发指令检测到正确语音,或者检测到对应的按键按下,单片机可以控制相应的外设进行工作同时WT588语音芯片可以语音相应的语音播报,并且OLED液晶显示屏可以显示对应的外设的状态,以及通过DHT11温湿度传感器实时检测到的当前室内的温湿度数据。
本设计的系统总框图如图所示。
- .1单片机的功能及最小系统的电路设计
本系统基于STM32F103系列单片机来实现功能,因为系统没有其它高标准的要求,我们最终选择了比较普遍的STM32F103C8T6单片机来实现系统设计。
STM32F103C8系列使用高性能的ARM® Cortex™-M3 32位的RISC内核,工作频率为72MHz,内置高速存储器(高达128K字节的闪存和20K字节的SRAM),丰富的增强I/O端口和联接到两条APB总线的外设。所有型号的器件都包含2个12位的ADC、3个通用16位定时器和1个PWM定时器,还包含标准和先进的通信接口:多达2个I2C接口和SPI接口、3个USART接口、一个USB接口和一个CAN接口。STM32F103列产品供电电压为2.0V至3.6V,包含-40°C至+85°C温度范围和-40°C至+105°C的扩展温度范围。一系列的省电模式保证低功耗应用的要求。
STM32F103系列产品提供包括从36脚至100脚的6种不同封装形式;根据不同的封装形式,器件中的外设配置不尽相同。下面给出了该系列产品中所有外设的基本介绍。这些丰富的外设配置,使得STM32F103系列微控制器适合于多种应用场合:
电机驱动和应用控制
医疗和手持设备
PC游戏外设和GPS平台
工业应用:可编程控制器(PLC)、变频器、打印机和扫描仪等
单片机的电路图如下图所示:
ARM®的Cortex™-M3核心并内嵌闪存和SRAM
ARM的Cortex™-M3处理器是最新一代的嵌入式ARM处理器,它为实现MCU的需要提供了低成本的平台、缩减的引脚数目、降低的系统功耗,同时提供卓越的计算性能和先进的中断系统响应。
ARM的Cortex™-M3是32位的RISC处理器,提供额外的代码效率,在通常8和16位系统的存储空间上发挥了ARM内核的高性能。
STM32系列拥有内置的ARM核心,因此它与所有的ARM工具和软件兼容。
内置闪存存储器
64K字节的内置闪存存储器,用于存放程序和数据。
2.1.1 CRC计算单元
CRC(循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个在众多的应用中,基于CRC的技术被用于验证数据传输或存储的一致性。在EN/IEC 60335-1标准的范围内,它提供了一种检测闪存存储器错误的手段,CRC计算单元可以用于实时地计算软件的签名, 并与在链接和生成该软件时产生的签名对比。
2.1.2内置SRAM
20K字节的内置SRAM,CPU能以0等待周期访问(读/写)。
2.1.3 嵌套的向量式中断控制器(NVIC)
STM32产品内置嵌套的向量式中断控制器,能够处理多达43个可屏蔽中断通道(不包括16个Cortex™-M3的中断线)和16个优先级。
紧耦合的NVIC能够达到低延迟的中断响应处理
中断向量入口地址直接进入内核
紧耦合的NVIC接口
允许中断的早期处理
处理晚到的较高优先级中断
支持中断尾部链接功能
自动保存处理器状态
中断返回时自动恢复,无需额外指令开销
该模块以最小的中断延迟提供灵活的中断管理功能。
2.1.5部中断/时间控制器
部中断/事件控制器包含19个边沿检测器,用于产生中断/事件请求。每个中断线都可以立地配置它的触发事件(上升沿或下降沿或双边沿),并能够单独地被屏蔽;有一个挂起寄存器维持所有中断请求的状态。EXTI可以检测到脉冲宽度小于内部APB2的时钟周期。多达80个通用I/O口连接到16个外部中断线。
2.1.6 时钟和启动
系统时钟的选择是在启动时进行,复位时内部8MHz的RC振荡器被选为默认的CPU时钟随后可以选择外部的、具失效监控的4~16MHz时钟;当检测到外部时钟失效时,它将被隔离,系统将自动地切换到内部的RC振荡器,如果使能了中断,软件可以接收到相应的中断。同样,在需要时可以采取对PLL时钟完全的中断管理(如当一个间接使用的外部振荡器失效时)。多个预分频器用于配置AHB的频率、高速APB(APB2)和低速APB(APB1)区域。AHB和高速APB的最高频率是72MHz,低速APB的最高频率为36MHz
2.1.7供电方案
VDD = 2.0~3.6V:VDD引脚为I/O引脚和内部调压器供电。
VSSA,VDDA = 2.0~3.6V:为ADC、复位模块、RC振荡器和PLL的模拟部分提供供电。使用ADC时,VDDA不得小于2.4V。VDDA和VSSA必须分别连接到VDD和VSS。
VBAT = 1.8~3.6V:当关闭VDD时,(通过内部电源切换器)为RTC、外部32kHz振荡器和后备寄存器供电。
2.1.8供电监控器
内部集成了上电复位(POR)/掉电复位(PDR)电路,该电路始终处于工作状态,保证系统在供电超过2V时工作;当VDD低于设定的阀值(VPOR/PDR)时,置器件于复位状态,而不必使用外部复位电路。器件中还有一个可编程电压监测器(PVD),它监视VDD/VDDA供电并与阀值VPVD比较,当VDD低于或高于阀值VPVD时产生中断,中断处理程序可以发出警告信息或将微控制器转入安全模式。PVD功能需要通过程序开启。
2.1.9电压调压器
调压器有三个操作模式:主模式(MR)、低功耗模式(LPR)和关断模式
主模式(MR)用于正常的运行操作低功耗模式(LPR)用于CPU的停机模式
关断模式用于CPU的待机模式:调压器的输出为高阻状态,内核电路的供电切断,调压器处于零消耗状态(但寄存器和SRAM的内容将丢失),该调压器在复位后始终处于工作状态,在待机模式下关闭处于高阻输出。
低功耗模式
STM32F103xC、STM32F103xD和STM32F103xE增强型产品支持三种低功耗模式,可以在要求低功耗、短启动时间和多种唤醒事件之间达到最佳的平衡。
睡眠模式
在睡眠模式,只有CPU停止,所有外设处于工作状态并可在发生中断/事件时唤醒CPU。
停机模式
在保持SRAM和寄存器内容不丢失的情况下,停机模式可以达到最低的电能消耗。在停机模式下,停止所有内部1.8V部分的供电,PLL、HSI的RC振荡器和HSE晶体振荡器被关闭,调压器可以被置于普通模式或低功耗模式。
可以通过任一配置成EXTI的信号把微控制器从停机模式中唤醒,EXTI信号可以是16个外部I/O 口之一、PVD的输出、RTC闹钟或USB的唤醒信号。
待机模式
在待机模式下可以达到最低的电能消耗。内部的电压调压器被关闭,因此所有内部1.8V部分的供电被切断;PLL、HSI的RC振荡器和HSE晶体振荡器也被关闭;进入待机模式后,SRAM和寄存器的内容将消失,但后备寄存器的内容仍然保留,待机电路仍工作。
从待机模式退出的条件是:NRST上的外部复位信号、IWDG复位、WKUP引脚上的一个上升边沿或RTC的闹钟到时。
2.1.10 DMA
灵活的7路通用DMA可以管理存储器到存储器、设备到存储器和存储器到设备的数据传输;DMA控制器支持环形缓冲区的管理,避免了控制器传输到达缓冲区结尾时所产生的中断。每个通道都有专门的硬件DMA请求逻辑,同时可以由软件触发每个通道;传输的长度、传输的源地址和目标地址都可以通过软件单独设置。DMA可以用于主要的外设:SPI、I2C、USART,通用、基本和高级控制定时器TIMx和ADC。
2.1.11 RTC和后备寄存器
RTC和后备寄存器通过一个开关供电,在VDD有效时该开关选择VDD供电,否则由VBAT引脚供电。后备寄存器(10个16位的寄存器)可以用于在关闭VDD时,保存20个字节的用户应用数据。RTC和后备寄存器不会被系统或电源复位源复位;当从待机模式唤醒时,也不会被复位。
实时时钟具有一组连续运行的计数器,可以通过适当的软件提供日历时钟功能,还具有闹钟中断和 阶段性中断功能。RTC的驱动时钟可以是一个使用外部晶体的32.768kHz的振荡器、内部低功耗RC 振荡器或高速的外部时钟经128分频。内部低功耗RC振荡器的典型频率为40kHz。为补偿天然晶体的偏差,可以通过输出一个512Hz的信号对RTC的时钟进行校准。RTC具有一个32位的可编程计数器,使用比较寄存器可以进行长时间的测量。有一个20位的预分频器用于时基时钟,默认情况下时钟为32.768kHz时,它将产生一个1秒长的时间基准。
2.1.12电压调压器定时器和看门狗
中等容量的STM32F103xx增强型系列产品包含1个高级控制定时器、3个普通定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。下表比较了高级控制定时器、普通定时器和基本定时器的功能:
定时器
计数器分辩率
计数器类型
预分频系数
产生DMA请求
捕获/比较通道
互补输出
TIM1
16位
向上,向下, 向上/下
1~65536之间的任意整数
可以
4
有
TIM2 TIM3 TIM4
16位
向上,向下, 向上/下
1~65536之间的任意整数
可以
4
没有
- 步进电机简介
步进电机作为执行原件是机电一体化的关键产品之一, 广泛应用在各种自动化控制系统中。随着微电子和计算机技术的发展,步进电机的需求量与日俱增,在各个国民经济领域都有应用。
步进电机是一种将电脉冲转化为角位移的执行机构。当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(称为“步距角”),它的旋转是以固定的角度一步一步运行的。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。步进电机可以作为一种控制用的特种电机,利用其没有积累误差(精度为100%)的特点,广泛应用于各种开环控制。
现在比较常用的步进电机包括反应式步进电机(vr)、永磁式步进电机(pm)、混合式步进电机(hb)和单相式步进电机等。永磁式步进电机一般为两相,转矩和体积较小,步进角一般为7.5度 或15度;反应式步进电机一般为三相,可实现大转矩输出,步进角一般为1.5度,但噪声和振动都很大。反应式步进电机的转子磁路由软磁材料制成,定子上有多相励磁绕组,利用磁导的变化产生转矩。
本设计采用的步进电机是混合式步进电机。混合式步进电机混合了永磁式和反应式步进电机的优点它又分为两相和五相:两相步进角一般为1.8度而五相步进角一般为 0.72度。这种步进电机的应用最为广泛。所以,本设计采用此种步进电机。
步进电机28BYJ-48型四相八拍电机,电压为DC5V—DC12V。当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或者两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态改变完成一个循环时,转子转过一个齿距。四相步进电机可以在不同的通电方式下运行,常见的通电方式有单(单相绕组通电)四拍(A-B-C-D-A。。。),双(双相绕组通电)四拍(AB-BC-CD-DA-AB-。。。),八拍(A-AB-B-BC-C-CD-D-DA-A。。。)
驱动方式:
表3.1 步进电机驱动方式
导线颜色
1
2
3
4
5
6
7
8
5红
+
+
+
+
+
+
+
+
4橙
—
—
3黄
—
—
—
2粉
—
—
—
1蓝
—
—
—
红线接电源5V,橙色电线接P1.3口,黄色电线接P1.2口,粉色电线接P1.1口,蓝色接P1.0口。
由于单片机接口信号不够大需要通过ULN2003放大再连接到相应的电机接口。
ULN2003晶体管阵列:
ULN2003是一个单片高电压、高电流的达林顿晶体管阵列集成电路。它是由7对NPN达林顿管组成的,它的高电压输出特性和阴极箝位二极管可以转换感应负载。单个达林顿对的集电极电流是500mA。达林顿管并联可以承受更大的电流。此电路主要应用于继电器驱动器,字锤驱动器,灯驱动器,显示驱动器(LED气体放电),线路驱动器和逻辑缓冲器。ULN2003的每对达林顿管都有一个2.7kΩ串联电阻,可以直接和TTL或5V CMOS装置。ULN2003的主要特点:
(1)500mA 额定集电极电流(单个输出)。
(2)高电压输出:50V。
(3)输入和各种逻辑类型兼容。
(4)步进电机驱动器。
利用ULN2003与单片机引脚相连,可以驱动步进电机。ULN2003的作用主要在于放大驱动电流,驱动28BYJ-48步进电机。ULN2003驱动的电机供电接口可以连接到单片机的GND和5V取电,“IN0~IN4”连接单片机的4个I/O口。
当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态的改变完成一个循环时,转子转过一个齿距。四相步进电机可以在不同的通电方式下运行。
28BYJ-48步进电机的齿轮减速比为64:1,转速约15转/分钟,一些软件采用某些手段和高电压电源(如12伏直流)也能达到约25转/分钟的转速。4步控制信号序列:11.25度/步,32步旋转一周。8步控制信号序列:5.625度/步,64步旋转一周。正常情况下,4步模式下旋转一周将用:32(步/周)x64(齿轮比)=2048步。
步进电机控制系统电路如图3.9所示:
图3.9 步进电机控制系统电路图
在实用两相混合式步进电机时需注意,该种电机在低速运转时有振动和噪声,是其固有的缺点、一般可采用以下方案来克服:
(1)如步进电机正好工作在共振区,可通过改变减速比等机械传动避开共振区;
(2)采用带有细分功能的驱动器,这是最常用的、最简便的方法;
(3)换成步距角更小的步进电机,如三相或五相步进电机;
(4)换成交流伺服电机,几乎可以完全克服震动和噪声,但成本较高;
(5)在电机轴上加磁性阻尼器,市场上已有这种产品,但机械结构改变较大。该模块采用四项五线步进电机,该电机是将电脉冲信号转变为角位移或线位移的开环控制元件。程序开始后,首先判断正反转,若为正转,则产生正转脉冲,判断是否完成,若未完成,则继续发出正转脉冲,若完成,则结束;若为反转,则发出反转脉冲,判断是否完成,若未完成,则继续发送反转脉冲,若完成,则结束。在本设计中步进电机驱动的部分原理图框图如下:
2.3 WT588语音播报简介
WT588D是一款具有单片机内核的语音芯片,因此,可以冠名为WT588D系列语音单片机。WT588D系列语音单片机是广州唯创科技有限公司联合台湾华邦共同研发出来的集单片机和语音电路于一体的可编辑语音芯片,功能强大的可重复擦除烧写的语音单片机芯片。内置13bit/DA转换器,以及12bit/PWM输出,音质好;PWM输出可直接推动0.5W/8Ω扬声器。
WT588D模块14脚串联了两个二极管作用是14脚VCC使用3.3V供电,所以串联了两个二极管分压,10、11、12直接接单片机引脚。BUSY输出:忙信号输出端,单片机可从BUSY输出来判断是否有音频输出。可设置为播放状态输出为高电平或低电平。高电平时电压接近VDD供电电压。
该模块采用WT588语音芯片,该芯片采用SPI三线接口与CPU进行同步通信。进入程序后,首先进行系统初始化设置;之后判断是否播报,若为否,则继续判断,若为是,则发送相应的命令;进行播报语音。在本设计中超声波测距的部分原理图框图如下:
![]()
![]()
2.4 温湿度传感器
DHT11传感器连接单片机相对比较简单。单片机的PA11口用来发收串行数据,即数据口。连接传感器的Pin2(单总线,串行数据)。由于测量范围电路小于20米,建议加一个3K的上拉电阻,因此在传感器的Pin2口与电源之间连接一个3K电阻。而传感器的电源端口Pin1和Pin4分别接单片机的VDD和GND端。传感器的第三脚悬浮放置。
DHT11的供电电压为3-5.5V,传感器上电后,要等待1s以越过不稳定状态在此期间无需发送任何指令。电源引脚(VDD,GND)之间也可增加一个100nF的电容,用以去耦滤波。数据用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右。DHT11与单片机连接图如下图所示:
![]()
DHT11主要通过单总线数据传输,DHT11第二引脚DOUT与单片机IO口相连,进行数据传输。当进入程序后,首先进行初始化,延时1S后,发送读取温湿度指令;之后延时4ms,再4ms内完成读取;通过单总线方式将数据传送给单片机,分析数据,得出温湿度值。其对应的程序流程图如下所示:
![]()
2.5 LD3320语音模块
LD3320芯片是一款“语音识别”专用芯片,由ICRoute公司设计生产。该芯片集成了语音识别处理器和一些外部电路,包括AD、DA转换器、麦克风接口、声音输出接口等。该芯片在设计上注重节能与高效,不需要外接任何的辅助芯片如Flash、RAM等,直接集成在现有的产品中即可以实现语音识别、声控、人机对话功能。并且,识别的关键词语列表是可以任意动态编辑的。
只需要把识别的关键词语以字符串的形式传送进芯片,即可以在下次识别中立即生效。比如,在单片机的编程中,简单地通过设置芯片的寄存器,把“你好”这样的识别关键词的内容动态地传入芯片中,芯片就可以识别这样设定的关键词语了。
原理图中加入了一个LED发光二极管,当LD3320发送给单片机语音信号时,LED点亮。用来提示有声音发送。
![]()
进入程序后,首先进行初始化设置,写入关键词,之后循环检测口令,判断口令是否正确,若为否,则重新开始循环检测口令。若为是,则开始定时,判断定时是否结束,若是,则重新开始循环检测口令,若为否,则判断是否有声音输入,若为否,则重新开始循环检测口令,若为是,则进行算法匹配,判断是否匹配出最佳结果,若为否,则重新开始循环检测口令,若为是,则发送最佳结果。
2.6 OLED液晶显示
有机发光二极管(缩写:OLED)又称有机电激发光显示(缩写:OLED)、有机发光半导体,OLED技术最早于1950年代和1960年代由法国人和美国人研究,其后索尼、三星和LG等公司于21世纪开始量产,与薄膜晶体管液晶显示器为不同类型的产品,前者具有自发光性、广视角、高对比、低耗电、高反应速率、全彩化及制程简单等优点,但相对的在大面板价格、技术选择性 、寿命、分辨率、色彩还原方面便无法与后者匹敌,有机发光二极管显示器可分单色、多彩及全彩等种类,而其中以全彩制作技术最为困难,有机发光二极管显示器依驱动方式的不同又可分为被动式与主动式有机发光二极管可简单分为有机发光二极管和聚合物发光二极管(polymer light-emitting diodes, PLED)两种类型,目前均已开发出成熟产品。聚合物发光二极管相对于有机发光二极管的主要优势是其柔性大面积显示。但由于产品寿命问题,目前市面上的产品仍以有机发光二极管为主要应用。
OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,并且能够节省电能,从2003年开始这种显示设备在MP3播放器上得到了应用。 以OLED使用的有机发光材料来看,一是以染料及颜料为材料的小分子器件系统,另一则以共轭性高分子为材料的高分子器件系统。同时由于有机电致发光器件具有发光二极管整流与发光的特性,因此小分子有机电致发光器件亦被称为OLED(Organic Light Emitting Diode),高分子有机电致发光器件则被称为PLED (Polymer Light-emitting Diode)。小分子及高分子OLED在材料特性上可说是各有千秋,但以现有技术发展来看,如作为监视器的信赖性上,及电气特性、生产安定性上来看,小分子OLED处于领先地位。当前投入量产的OLED组件,全是使用小分子有机发光材料。系统中OLED的电路图如下图所示:
液晶显示模块采用OLED显示屏,该模块采用四线SPI接口方式和单片机通信。程序开始后,首先对OLED进行初始化设置,之后进入显示函数,首先选择OLED显示的位,然后找到对应这个位置需显示的数据,最后,在这个位置打印出数据。一次只显示一个位,因为刷新速度较快,我们人眼看到的就是能显示出好多位。
第三章 软件设计
3.1 开发环境
STM32单片机软件开发平台为Keil5,和STM32CubeMx,Keil5是美国Keil Software公司出品的32系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。Keil5提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。运行Keil5软件需要WIN98、NT、WIN2000、WINXP等操作系统。
STM32CubeMX是一个图形化的工具,也是配置和初始化C代码生成器(STM32 configuration and initialization C code generation ) ,也就是自动生成开发初期关于芯片相关的一些初始化代码。它包含了STM32所有系列的芯片,包含示例和样本( Examples and demos )、中间组件( MiddlewareComponents )、硬件抽象层(Hardwaree abstraction layer )。
STM32CubeMX是ST意法半导体的主动原创工具,它可以减轻开发的时间和费用。STM32CubeMX集成了一个全面的软件平台,支持STM32每一个系列的MCU开发。这个平台包括STM32Cube HAL(一个STM32的抽象层集成软件,确保STM32系列最大的移植性)。再加上兼容的一套中间件(RTOS、USB、TCPI/IP和图形),所有内嵌软件组件附带了全套例程。其特性如下所示:
1、直观的选择STM32微控制器。2、微控制器图形化配置
3、C代码工程生成器覆盖了STM32微控制器初始化编译软件,如IAR,Keil,GCC。
4、可独立使用或作为Eclipse使用。
3.2 系统软件设计语言
本次设计用C语言作为程序软件设计语言它的特点就是可以尽量减少你对硬件进行操作C语言具有良好的程序结构适用于模块化程序设计,因此采用C语言设计单片机应用系统程序时,首先要尽可能地采用结构化的程序设计方法将功能模块化由不同的模块完成不同的功能这样可使整个应用系统程序结构比较清晰,易于调试和维护。不同的功能模块分别指定相应的入口参数和出口参数对于一些要重复调用的程序一般把其编成函数。这样可以减少程序代码的长度又便于整个程序的管理还可增强可读性和移植性。
3.3 Altium Designer应用
Altium Designer是PORTEL公司在80年代末推出的EDA软件。Altium Designer是应用于Windows9X/2000/NT操作系统下的EDA设计软件,采用设计库管理模式,可以网设计,具有很强的数据交换能力和开放性及3D模拟功能,是一个32位的设计软件,可以完成电路原理图设计,印制电路板设计和可编程逻辑器件设计等工作,可以设计32个信号层,16个电源--地层和16个机加工层。
Altium Designer软件的特点:
可生成30多种格式的电气连接网络表;
强大的全局编辑功能;
在原理图中选择一级器件,PCB中同样的器件也将被选中;
同时运行原理图和PCB,在打开的原理图和PCB图间允许双向交叉查找元器件、引脚、网络
既可以进行正向注释元器件标号(由原理图到PCB),也可以进行反向注释(由PCB到原理图),以保持电气原理图和PCB在设计上的一致性;
满足国际化设计要求(包括国标标题栏输出,GB4728国标库); * 方便易用的数模混合仿真(兼容SPICE 3f5);
支持用CUPL语言和原理图设计PLD,生成标准的JED下载文件; * PCB可设计32个信号层,16个电源-地层和16个机加工层;
强大的“规则驱动”设计环境,符合在线的和批处理的设计规则检查;
智能覆铜功能,覆铀可以自动重铺;
提供大量的工业化标准电路板做为设计模版;
放置汉字功能;
可以输入和输出DXF、DWG格式文件,实现和AutoCAD等软件的数据交换;
智能封装导航(对于建立复杂的PGA、BGA封装很有用);
方便的打印预览功能,不用修改PCB文件就可以直接控制打印结果;
3.4 系统软件设计心得
程序设计有其规律和共同点。在编写程序时采取如下几个步骤
1明确设计所要实现的功能将软件的设计分成若干个独立的模块。便于编程和修改查询。根据时序关系和功能关系设计出最合理的软件总体结构
2依照所设定的程序流程图和指令系统编写程序,注意在程序相关部位标注注释。提升程序的可读性。
3系统资源合理的分配,按照要实现的功能选择。
4通过编辑软件编辑出的源程序,必须用编译程序汇编后生成目标的代码。如果源程序有语法错误那么需修改源文件后继续编译,直到无语法错误为止然后利用目标代码通。过仿真器进行程序调试排除设计和编程中的错误直到成。
参考文献
[1] 朱清慧 编著 .基于Proteus显示控制系统设计与实例.北京:清华大学出版社,2011
[2] 清华大学电子学教研组编 . 杨素行主编 . 模拟电子技术基础简明教程 . 3版 .北京:高等教育出版社,2005
[3] 张亚华. 电子电路计算机辅助分析与辅助设计. 北京 航空工业出版社,2004
[4] 莫正康. 电力电子应用技术. 北京:机械工业出版社,2009
[5] 曾晓宏. 数字电子技术. 北京:机械工业出版社,2008
[6] 江晓安. 模拟电子技术. 陕西:西安电子科技大学出版社,2007
[7]蒋辉平 周国雄. 基于Proteus的单片机系统设计与仿真实例 北京:机械工业出版社,2009
[8]王宗培.步进电动机及其控制系统[M].哈尔滨:哈尔滨工业大学出版社,2009
[9]余永权.单片机应用系统的功率接口技术[M].北京:北京航空航天大学出版社,2006
[10]陈理壁.步进电机及其应用[M].上海:上海科学技术出版社,2009
[11] 王晓明、 胡晓柏,电动机的单片机控制[M].北京航空航天大学出版社,2002年5月第1版:181-208
[12] 刘宝延、 程树康,步进电动机及其驱动控制系统 [M] .2007年11月第一版:134-167
[13] 史敬灼, 步进电动机伺服控制技术[M] .2007年3月第2版:23-35
[14]刘国永, 陈杰平. 单片机控制步进电机系统设计. 安徽: 安徽技术师范学院学报, 2012, 16 (4) : 61-63.
[15]孙笑辉,韩曾晋. 减少感应电动机直接转矩控制系统转矩脉动的方法[J]. 电气传动, 2011 (1) : 8-11.
致 谢这篇论文的制作历时了两个月的时间,在论文的写作过程中遇到了无数的困难和障碍,都在同学和老师的帮助下度过了。尤其要强烈感谢同学们,在整个论文实践和论文写作的过程中,他们都对我进行了无私的指导和帮助,有的同学手把手教我焊电路板,由于我不熟练,焊坏了好几块板子,可他们还是鼓励我。还有的同学帮我调试程序,有时一个程序要连续调好几个小时,他们很有耐心,一边调试一边给我讲程序的道理,我获益匪浅。另外,在校图书馆查找资料的时候,图书馆的老师也给我提供了很多方面的支持与帮助。还要感谢指导老师关学忠教授及学长不厌其烦的帮助我进行论文的修改和改进。还有我大学四年来教导过我的所有老师,为我打下了专业知识的基础,在此向所有帮助和指导过我的各位老师表示最衷心的感谢!
感谢这篇论文所涉及到的各位学者。本文引用了许多学者的研究文献,如果没有各位学者的研究成果的帮助和启发,我将很难完成本篇论文的写作。
最后,衷心的感谢在百忙之中评阅论文和参加答辩的各位老师,请您们对论文的不足进行批评和指正。
附录 A
图A1 系统总体电路图
图A2 系统总体PCB图
附录 B
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "oledisp.h" //
#include "step.h"
#include "bsp_DHT11.h"
#include "wt588.h"
#include "FLSH.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint16_t TSnum= 0 ;
uint8_t reckey = 0; //串口接收语音指令
void key()
{
static uint8_t keyF1 = 0 ,keyF2 = 0 ,keyF3 = 0 ,keyF4 = 0 ,keyF5 = 0 ; //防止连按标志位
if(key1 == 0 )
{
if(keyF1)
{
keyF1 = 0 ;
ledwut; //控制雾灯
if(ledwuR )
{
Send_threelines(17); //灯已关
}
else
{
Send_threelines(18); //灯已开
}
writeF = 1 ; //开始存储
}
}
else
{
keyF1 = 1 ;
}
if(key2 == 0 )
{
if(keyF2)
{
keyF2 = 0 ;
fant; //控制风扇
if(fanR == 0 )
{
Send_threelines(19); //已关
}
else
{
Send_threelines(20); //已开
}
writeF = 1 ; //开始存储
}
}
else
{
keyF2 = 1 ;
}
if(key3 == 0 )
{
if(keyF3)
{
keyF3 = 0 ;
direction =! direction; //控制窗帘
if(direction )
{
Send_threelines(12); //已关
}
else
{
Send_threelines(13); //已开
}
writeF = 1 ; //开始存储
}
}
else
{
keyF3 = 1 ;
}
if(key4 == 0 )
{
if(keyF4)
{
keyF4 = 0 ;
JDQt; //控制开关
if(JDQR == 0 )
{
Send_threelines(21); //已关
}
else
{
Send_threelines(22); //已开
}
writeF = 1 ; //开始存储
}
}
else
{
keyF4 = 1 ;
}
if(key5 == 0 )
{
if(keyF5)
{
keyF5 = 0 ; //
Send_threelines(15); // 当前温度为
if(DHT11Now.temperature > 9 )
{
if(DHT11Now.temperature/10%10 > 1 ) Send_threelines( DHT11Now.temperature/10%10); //
Send_threelines(10); //
}
if((DHT11Now.temperature > 9 && DHT11Now.temperature%10 >0)|| DHT11Now.temperature < 10)
{
Send_threelines( DHT11Now.temperature%10); //
}
Send_threelines(16); //
Send_threelines(14); // 当前湿度为
Send_threelines(11); //
if(DHT11Now.humidity > 9 )
{
if(DHT11Now.humidity/10%10 > 1 ) Send_threelines( DHT11Now.humidity/10%10); //
Send_threelines(10); //
}
if((DHT11Now.humidity > 9 && DHT11Now.humidity%10 >0)|| DHT11Now.humidity < 10)
{
Send_threelines( DHT11Now.humidity%10); //
}
}
}
else
{
keyF5 = 1 ;
}
}
void display()
{
char TS[10] = {0} ;
location(0,0) ; //设置显示位置
display_GB2312_string(" 温度:"); //显示字符
sprintf(TS,"%d℃", DHT11Now.temperature ) ;
display_GB2312_string(TS); //显示字 符
location(1,0) ; //设置显示位置
display_GB2312_string(" 湿度:"); //显示字符
sprintf(TS,"%d", DHT11Now.humidity ) ;
display_GB2312_string(TS); //显示字符
display_GB2312_string("%"); //显示字符
location(2,0) ; //设置显示位置
display_GB2312_string(" 灯:"); //灯
if(ledwuR)
{
display_GB2312_string("关 "); //
}
else
{
display_GB2312_string("开 "); //
}
display_GB2312_string(" 风扇:"); //
if(fanR == 0 )
{
display_GB2312_string("关"); //
}
else
{
display_GB2312_string("开"); //
}
location(3,0) ; //
display_GB2312_string("窗帘:"); //
if(direction)
{
display_GB2312_string("关 "); //显示字符
}
else
{
display_GB2312_string("开 "); //显示字符
}
display_GB2312_string(" 开关:"); //显示字符
if( JDQR == 0 )
{
display_GB2312_string("关"); //显示字符
}
else
{
display_GB2312_string("开"); //显示字符
}
}
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/********************************************
可以在任何地方添加定时器回调函数
***********************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint16_t timCount = 0 ;
if(htim == &htim1)
{
timCount = (timCount + 1)%10000 ;
if(timCount%6 == 0)
{
}
if(timCount%20 == 0)
{
}
}
if(htim == &htim2)
{
motor(); //放定时器中断,驱动点击
}
}
/* 使能接收,进入中断回调函数 接收到一个字节进入中断*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart3)
{
HAL_UART_Receive_IT(&huart3,&reckey,1);
}
}
void uartback()
{
static uint32_t getTS = 0 ;
if((HAL_GetTick() - getTS ) < 8000) //三秒内可以接收指令
{
switch(reckey )
{
case 1 : //开灯
ledwu(0)
Send_threelines(18); //灯已开
break ;
case 2 : //关灯
ledwu(1)
Send_threelines(17); //灯已关
break ;
case 3 : //打开风扇
fan(1)
Send_threelines(20); //已开
break ;
case 4 : //关闭风扇
fan(0)
Send_threelines(19); //已关
break ;
case 5 : //打开窗帘
direction = 0 ;
Send_threelines(13); //已开
break ;
case 6 : //关闭窗帘
direction = 1 ;
Send_threelines(12); //已关
break ;
case 7 : //打开开关
JDQ(1)
Send_threelines(22); //已开
break ;
case 8 : //关闭开关
JDQ(0)
Send_threelines(21); //已关
break ;
case 9 : //打开所有设备
ledwu(0)
JDQ(1)
fan(1)
direction = 0 ;
Send_threelines(24); //已关
break ;
case 10 : //关闭所有设备
ledwu(1)
JDQ(0)
fan(0)
direction = 1 ;
Send_threelines(25); //已关
break ;
case 11 :
Send_threelines(15); // 当前温度为
if(DHT11Now.temperature > 9 )
{
if(DHT11Now.temperature/10%10 > 1 ) Send_threelines( DHT11Now.temperature/10%10); //
Send_threelines(10); //
}
if((DHT11Now.temperature > 9 && DHT11Now.temperature%10 >0)|| DHT11Now.temperature < 10)
{
Send_threelines( DHT11Now.temperature%10); //
}
Send_threelines(16); //
Send_threelines(14); // 当前湿度为
Send_threelines(11); //
if(DHT11Now.humidity > 9 )
{
if(DHT11Now.humidity/10%10 > 1 ) Send_threelines( DHT11Now.humidity/10%10); //
Send_threelines(10); //
}
if((DHT11Now.humidity > 9 && DHT11Now.humidity%10 >0)|| DHT11Now.humidity < 10)
{
Send_threelines( DHT11Now.humidity%10); //
}
break ;
default:
break ;
}
}
else
{
ledyy(1)
}
if(reckey== 66 ) //收到唤醒词
{
getTS = HAL_GetTick() ;
ledyy(0)
Send_threelines(23); //在呢
}
if(reckey < 12 &&reckey )
{
ledyy(1)
writeF = 1 ; //开始存储
getTS = 0 ;
}
reckey = 0 ; //没有语音唤醒时,强制清零
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart3,&reckey,1);
HAL_TIM_Base_Start_IT(&htim1); //主函数中添加打开定时器中断
HAL_TIM_Base_Start_IT(&htim2); //主函数中添加打开定时器中断
WT588_GPIO_Init(); //初始化WT588用到的IO口
step_GPIO_Init() ; //步进电机IO口 初始化
initial_lcd(); //初始化lcd
readMomerr() ; //上电读取存储值
while (1)
{
uartback() ;
key() ;
display();
DHT11_Read_TempAndHumidity(&DHT11Now); //检测温湿度
writeMomerr(); //等待存储
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
int fputc(int ch,FILE *f)
{
uint8_t temp[1] = {ch};//
HAL_UART_Transmit(&huart3,temp,1,500);
return ch ;
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
![]()