本文是作者原创文章,欢迎转载,请注明出处 from:@Eric_Lai

写在前面

刚开学,马上来三周的课程设计,主题是一个以单片机为主的机电系统。我一直对智能家居这个方向很感兴趣,毕业设计也打算做这个,刚好先拿这个课设来练练手了。二话不说,和舍友马上组队开始刷怪。

经过三周(其实是两周,中间因为考试复习了一周,没干事儿)“艰苦的奋斗”,也算低空掠过完成这个小demo,下面是记录在开发过程当中的一些问题,以及解决方案。

架构设计

我们的想法是这样的,搭建一个模拟家里的环境,然后用一些电机和伺服电机模拟家庭里面的一些设备,提供两种控制方式来进行控制。这两种控制方式分别是:

整个系统里面,下位机采用ST公司的STM32芯片作为MCU,上位机方面采用一个搭载了Android系统的智能手机。为了要驱动电机和伺服电机当然需要一些驱动芯片了。

程序设计方面,主程序一直保持着空的状态,随时蓝牙传输过来的数据进入串口中断,或者响应由硬件按钮和开关触发的外部中断。

这也就意味着要有一个Android下的应用专门用于控制。另外,还需要有上位机和下位机的通信。本着能省则省得原则,通信就用蓝牙来实现了。刚好,学习了几个月的Android,我也有机会实战一下。

然而,这里让我吐槽一下。我学Android的原因就是为了逃避硬件,每每做硬件的时候的调试都能把我气个半死。没想到,学个Android的应用还是要和蓝牙打交道。吐槽归吐槽,活还是得继续做的。

构思了之后,我们整体的框架打算按照下面的图片展示那样来构建。

framework

硬件开发篇

这里接下去的内容将会是我在开发硬件过程当中遇到的一些坑爹问题,特别记录下来,防止以后再次掉进这些个大坑里面。

STM32的开发环境选用的是keil4,十分蛋疼的一个开发环境,自从用惯了有代码补全的IDE之后再回来用这种单片机的开发环境就觉得十分的不顺手,还经常打错函数名字,果然是懒癌末期了。恩,还有交代一下,程序烧录和调试用的是Jlink。

反转法进行矩阵键盘的检测

为什么要有这个键盘的检测呢,因为根据我们的设定,打算在门禁的地方设一个密码锁,输入正确的密码就可以控制门自行打开。所以,我们需要一个有0~9的数字的键盘,另外还需要一个确定按钮和取消按钮。

首先,扫一下盲,什么是矩阵键盘呢?就是把键盘按照一定的方式连接起来的方法,分为行和列。而不是一个键盘使用一个单片机的引脚。具体的连接原理图如下所示:

矩阵键盘原理图

从上图可以看到,这是一个4*4的矩阵键盘,我们习惯把V1~V5称为行线,把H1~H称为列线。然后每个引脚都接上一个上拉电阻,行线和列线之间通过一个键盘来连接。没有按下去前行线和列线不通,按键按下去后导通。

说完这个,下面我们可以研究一下检测的原理。怎么样准确的定位到是哪一个按键被按下去了。在这里,定位一个按键是通过行线和列线来确定的。我们所使用的反转法原理如下(使用的MCU是STM32):

以上,就是反转法检测矩阵键盘的原理了。记得要开漏输出的引脚写0,并且进入中断之后要屏蔽外部中断。

使用蓝牙模块进行通信

上位机如果要控制下位机的话就必须要有一个数据的交互,为了完成数据交互的功能,我们选择使用蓝牙技术。Android方面,现在基本上不是脑残的智能手机都配有蓝牙,所以我们只需要在STM32这边接上一个蓝牙模块即可实现。对蓝牙的控制,我们将它玩完全的当做一个异步的串行通信接口即可。使用的时候大体的步骤应该如下(使用库函数开发):

最后是配置中断控制器NVIC(步骤和上述差不多,最后记得提交结构体):

NVIC_InitTypeDef NVIC_InitStructure; 
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure);

其中接的使能接收中断,使用以下的语句即可:

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

使用蓝牙模块,我们不需要关心它的底层,它是怎么接收和发送数据的我们并不关心。我们需要关心的是怎么获得它接收到的数据,为了保证Android对下位机的控制,这里我们需要对STM32的中断进行优先级配置,将串口的接收中断配置为最高优先级(具体见上述代码的Proirity处,都设置成了0。注意,0是最高优先级)。

为了方便调试,我还设置了一个printf函数,可以通过串口监控程序执行到哪里了。对于STM32的开发这个设置我觉得特别有必要,毕竟这个不像在PC上的集成开发环境,可以有日志或者控制台可以随时对程序进行监控。想要设置这个也不难,我们需要包含C的微机开发库,在设置(keil下一个像锤子一样的图标里,在使用c-lib前面打一个勾即可),另外还要重新定向printf的输出,让它通过串口来输出数据。重写如下函数即可:

int fputc(int ch, FILE *f){
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 
	USART_SendData(USART1, (uint8_t) ch);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
	return (ch);
}

其他

在这个项目里面,我们还用了一些舵机和电机,不过这些都没有什么好说的。相信控制这些还是比较简单的。主要就是通过通用定时器输出一定频率的PWM即可实现。需要输出的PWM也是有公式计算的,这里就不一一多说了。

下一篇将开始讲述Android端的开发,这是我第一次用Android的蓝牙,所以我也是绕了不少弯路。到时候会记录下来,大家一起学习。