所用硬件设备:
1.电脑
2.STM32嵌入式最小系统——其实51控制成本会更低,也同样稳定。(* ̄︶ ̄)
3.HC-SR501 RD-624人体红外感应电子模块 淘宝上多的一塌糊涂,几块钱即可购买
4.USB-TTL下载器
就这几个,其他的应该没有了。
如何实现呢?步骤如下:
1.硬件接线
先介绍一下这个人体感应模块
它与STM32的PC0口相连。模块的正极接在了+5V上,负极接在了GND上。
2.STM32数据采集,软件实现
我们通过串口1实现数据的采集,并将采集的数据通过串口发送到电脑,STM32的代码如下:
#include"stm32f10x.h"
#include"stdarg.h"
void GPIOC_Init_Body(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); // 开启时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 开启PC0口
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU ; // 上拉输入
GPIO_Init(GPIOC,&GPIO_InitStruct); // 初始化
}
void USART1_Config()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能USART1的始时钟 和 GPIOA时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA , ENABLE);
/* 配置USART1 TX,并设置为复用推挽输出模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置USART1 RX,并设置为浮空输入模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置USART1模式 */
USART_InitStructure.USART_BaudRate = 57600; //波特率设置为57600//
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //配置串口传输的字长8位//
USART_InitStructure.USART_StopBits = USART_StopBits_1; //配置停止位为1//
USART_InitStructure.USART_Parity = USART_Parity_No; //不设置奇偶校验位//
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不采用硬件流//
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //配置串口为双线全双工通信,将RX,TX模式都开启//
USART_Init(USART1, &USART_InitStructure); //向寄存器写入配置参数//
USART_Cmd(USART1, ENABLE); //使能USART1外设//
}
static char *itoa(int value, char *string, int radix)
{
int i, d;
int flag = 0;
char *ptr = string;
/* 此实现只适用于十进制 */
if(radix != 10)
{
*ptr = 0;
return string;
}
if(!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
/* 如果这是负值,则插入减号 */
if(value < 0)
{
*ptr++ = '-';
value *= -1;
}
for(i = 10000; i > 0; i /= 10)
{
d = value / i;
if (d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
/* NULL终止字符串 */
*ptr = 0;
return string;
}
void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while (*Data != 0) //判断是否到达字符串结束符//
{
if(*Data == 0x5c) //'\'//
{
switch( *++Data )
{
case 'r': //回车符//
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //换行符//
USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if (*Data == '%')
{
switch (*++Data)
{
case 's': //字符串//
s = va_arg(ap, const char *);
for(;*s; s++)
{
USART_SendData(USARTx, *s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
case 'd': //十进制//
d = va_arg(ap, int);
itoa(d, buf , 10);
for(s = buf;*s;s++)
{
USART_SendData(USARTx, *s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
}
else USART_SendData(USARTx, *Data++);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
}
void delay(void)
{
int i,j;
for(i=0;i<10000;i++)
{
for(j=0;j<1000;j++);
}
}
int main(void)
{
/*初始化串口*/
USART1_Config();
GPIOC_Init_Body();
USART1_printf(USART1,"\r\nHello World\r\n");
while(1)
{
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0) == 1)
{
USART1_printf(USART1,"PEOPLE");
}
else
{
USART1_printf(USART1,"NO PEOPLE");
}
delay();
}
}
电脑侧收到的数据如下:
数据接收没什么问题。
3.电脑端程序实现
首先,要准备好资源。我们这里准备了一个MP4格式的资源,然后通过C语言打开运行,简单代码如下:
#include"stdio.h"
#include"stdlib.h"
#include<windows.h>//ShellExecute函数的头文件
int main()
{
char function[]="F:\\C_study\\o3_Open_EXE\\sscom42.exe";
int aa=0;
//ShellExecute(NULL,"open","F:\\C_study\\o3_Open_EXE\\ooopic_1569149000.ico",NULL,NULL,SW_MAX); // 打开图片
//ShellExecute(NULL,"open","F:\\C_study\\o3_Open_EXE\\DSC_0230.JPG",NULL,NULL,SW_SHOWNORMAL); // 打开exe文件
ShellExecute(NULL,"open","F:\\C_study\\o3_Open_EXE\\789.mp4",NULL,NULL,SW_SHOW);
printf("aa = %d\n",aa);//system函数有返回值:成功返回1,失败返回0;1时,代表程序已经打开。
printf("Please waiting for.......");
return 1;
}
其次,需要关闭这个MP4文件,这时我们通过关闭进程的方式来实现,简单代码如下:
#include"stdio.h"
#include"stdlib.h"
#include<windows.h>//ShellExecute函数的头文件
int main()
{
system("taskkill /f /im wmplayer.exe"); // 关闭指定进程
return 0;
}
最后,是综合实现,依据STM32传过来的数据来判断是否要打开视频广告,或关闭视频广告。
我们这里设定,没有人时(NO PEOPLE)采集20次以上后,则实现视频广告播放
有人时(PEOPLE)采集5次以上后,则关闭视频广告,回到用户的操作页面。
这种应用场景还是比较多的,毕业无人售票机,公司,学校,银行等一些无人办事机,都可以实现这样的功能。
代码如下(这个是将上两个C语言代码综合起来实现的):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <conio.h>
#include "tchar.h"
#include "stdlib.h" // wt modify 2019.4.4
char com[10][10] = {"COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","COM10"};
int main()
{
int i;
int people=0,nopeople=0;
char flag=0; // 标记位
HANDLE hCom;
for(i=0;i<10;i++)
{
hCom = CreateFile(_T(com[i]),//COMx口
GENERIC_READ | GENERIC_WRITE,//允许读和写
0,//独占方式
NULL,
OPEN_EXISTING,//打开而不是创建
0,//同步方式
NULL);
if(hCom == (HANDLE)-1)
{
printf("打开COM%d失败!\n",(i+1));
if(9 == i)
{
return FALSE;
}
continue;
}
else
{
printf("COM%d打开成功!\n",(i+1));
break;
}
}
SetupComm(hCom, 20480, 20480);//输入缓冲区和输出缓冲区的大小都是1024
COMMTIMEOUTS TimeOuts;//设定读超时
TimeOuts.ReadIntervalTimeout = 100;
TimeOuts.ReadTotalTimeoutMultiplier = 500;
TimeOuts.ReadTotalTimeoutConstant = 5000;
TimeOuts.WriteTotalTimeoutMultiplier = 500;//设定写超时
TimeOuts.WriteTotalTimeoutConstant = 2000;
SetCommTimeouts(hCom, &TimeOuts);//设置超时
DCB dcb1;
GetCommState(hCom, &dcb1);
dcb1.BaudRate = 57600;//波特率为115200
dcb1.ByteSize = 8;//每个字节有8位
dcb1.Parity = NOPARITY;//无奇偶校验位
dcb1.StopBits = TWOSTOPBITS;//两个停止位
dcb1.fParity = FALSE;
dcb1.fNull = FALSE;
SetCommState(hCom, &dcb1);
DWORD wCount = 256;//读取的字节数
DWORD wCount1;
PurgeComm(hCom, PURGE_TXCLEAR|PURGE_RXCLEAR);//清空缓冲区
//WinExec("F:\\C_study\\o2_USB_Advertisement\\source\\OpenEXE.exe", SW_MAXIMIZE);
while(1)
{
int i = 0;
FILE *fp1;
char str[256];
int len=0; // wt
if(!ReadFile(hCom, str, wCount, &wCount1, NULL))
{
printf("读串口失败!");
return FALSE;
}
fp1 = fopen("串口发送的数.txt", "a+");
printf("读串口成功!\n");
if(wCount1 > 0)
{
}
else
{
}
printf("读取长度为:%d\n", wCount1);
printf("读取数据为:\n");
//for(i=0; i< wCount1; i++)
//{
//printf("%c", str[i]); // 输出
//fprintf(fp1, "%c", str[i]); // 写入文件
//}
printf("\n");
str[wCount1] = '\0';
printf("%s", str); // 字符串输出
printf("\n");
if(strcmp(str,"NO PEOPLE") == 0) // wt 判断是否有人
{
nopeople++;
if(nopeople>20)
{
if(flag == 0) // 让其正常播放,不要反复打开广告
{
WinExec("F:\\C_study\\o2_USB_Advertisement\\source\\OpenEXE.exe", SW_SHOWNORMAL);
printf("打开广告\n");
flag = 1; // 置位 不让反复打开广告
}
nopeople=0; // 置位
people = 0;
}
}
else if(strcmp(str,"PEOPLE") == 0)
{
people++;
if(people>5)
{
WinExec("F:\\C_study\\o2_USB_Advertisement\\source\\CloseEXE.exe", SW_SHOWNORMAL);
printf("关闭广告\n");
people = 0; // 置位
nopeople = 0;
flag = 0 ; // 置零,下次无人的时候正常打开广告
}
}
fclose(fp1);
}
CloseHandle(hCom);
std::cout << "Hello World!\n";
return 0;
}
每次运行这个C/C++语言程序,效果如图:
没有人采集超过20次时,就会打开广告。
当有人来时采集超过5次以上,就会关闭广告。
这样就实现了需要实现的效果,其实还可以进一步添加功能。