IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于STM32的微信视频电话拨号器,让家里的老人也能轻松使用微信视频电话 -> 正文阅读

[嵌入式]基于STM32的微信视频电话拨号器,让家里的老人也能轻松使用微信视频电话

前言

如今智能信息时代发展迅猛,年轻一代享受着时代红利,而上了年纪的长辈却越来越迷茫,对于智能手机根本搞不清使用方法,很多老人只能退而求其次,使用老人机满足打电话这样的就基本需求,同时老人机存在很多局限:有时老人家会因为心痛电话费刻意控制时长;大多数老人机只能打电话,不能视频通话。如今网络如此发达,微信作为全球统一的及时通讯软件,不但通话免费,还能打视频电话,为何不开发针对老人的微信版本呢?只知道儿童智能手表可以打微信电话,但还是无法满足所有痛点,开造:

项目说明

思路:基于STM32的USB鼠标控制手机完成自动化控制操作,一般的手机都支持USB OTG功能。但OTG功能存在一个很大的弊端,就是无法边充电边使用,本文设计功能切换电路解决了这一问题,可闲时给手机充电。制作此项目需要参考我的前两篇博文。

所需材料

  • 旧安卓智能手机
  • 5pin的MicroUSB接头
  • 矩阵键盘
  • STM32F103C8T6最小系统板
  • 手机支架
  • mos管或继电器
    在这里插入图片描述

一、先看成果

在这里插入图片描述
在这里插入图片描述

  • 键盘功能配置
123A
选择联系人1选择联系人2选择联系人3解锁
456B
选择联系人4选择联系人5选择联系人6进入微信
789C
选择联系人4选择联系人5选择联系人6开始呼叫
*0#D
解锁并进入微信选择联系人0开始呼叫结束通话
  • 呼叫流程
解锁
进入微信
选择联系人
开始呼叫
结束通话

二、硬件设计

1 接线示意图

在这里插入图片描述

1.1 矩阵键盘

矩阵键盘内部接线示意图如下:
在这里插入图片描述

1.2 MicroUSB OTG接口功能切换电路

MicroUSB有5个引脚,其中两个用来供电(VCC、GND),两个用来传输数据(D+、D-),还有一个ID引脚是用来选择OTG功能的。当ID接地时,手机会启用OTG功能,当ID悬空时为普通数据线功能。经过反复实验,发现手机在MicroUSB刚插入时才检测是否开启OTG功能,为了**模拟插入和拔出的操作,用MOS管来断电,用单片机控制ID引脚的电平,实现功能切换,达到空闲时充电的目的。**手头只要一颗IRF540N的N型MOS管,只能用如下电路控制。

在这里插入图片描述
根据数据手册,此MOS管过于大材小用,VDSS = 100V RDS(on) = 44m? ID = 33A。
同时VGSth在2-4V之间,而单片机IO在输出电压为3.3V,虽然在这个范围内,但为了使MOS能够完全导通,利用开漏输出功能配合上拉电阻可将IO口输出电压提高到5V。
在这里插入图片描述

2 焊接

为了省去焊接的麻烦,画了一个PCB板,第一板存在一些小问题(没有画入MOS管,加入了音频功放功能作为拓展可以忽略),以上述接线图为准。
在这里插入图片描述

三、软件设计

根据此文章配置好USB鼠标程序框架

结合此文章添加矩阵键盘功能

根据此文章配置好USB鼠标程序框架

1 引脚配置

根据以上配置好USB鼠标后配置键盘引脚和USB OTG功能切换控制引脚。
将键盘的8个引脚全部配置为上拉模式,其中4个为输出口、4个为输入口
在这里插入图片描述
将USB OTG控制的两个引脚配置为开漏输出,可修改名称方便阅读
在这里插入图片描述

2.1 修改usb_device.c文件

在编写鼠标控制程序时发现鼠标只能相对移动,无法移动绝对位置,而点击屏幕最重要的时移动到屏幕指定位置。为了解决这一问题,本文采用的方案为:

一直移动到最左上角
设为原点
相对移动
计算绝对位置

添加静态变量

/* USER CODE BEGIN 0 */
static int16_t Px=0,Py=0;//绝对位置
static uint8_t L=0,R=0,M=0;//鼠标上三个按键状态
/* USER CODE END 0 */

添加鼠标基本控制函数

/* USER CODE BEGIN 1 */
//发送鼠标所有控制信息
void Set_Mouse(int8_t x,int8_t y,int8_t z,uint8_t l,uint8_t r,uint8_t m)
{
	uint8_t buf[4] = {0,0,0,0};
	L=l;R=r;M=m;
	buf[0] = L+R*2+M*4;
	buf[1]=x;
	buf[2]=y;
	buf[3]=z;
	USBD_HID_SendReport(&hUsbDeviceFS,buf,4);
	HAL_Delay(100);
}
//滚轮滚动
void Scroll(int8_t z)
{
	Set_Mouse(0,0,z,L,R,M);
}
//鼠标相对移动
void Move(int8_t x,int8_t y)
{
	Px += x;
	Py += y;
	
	if(Px<0)Px=0;
	if(Py<0)Py=0;
	if(Px>=PX_MAX-1)Px=PX_MAX-1;
	if(Py>=PY_MAX-1)Py=PY_MAX-1;
	
	Set_Mouse(x,y,0,L,R,M);
}
//鼠标移动到最左上角
void Move_Reset(void)
{
	uint8_t i=16;
	while(i--)Move(-120,-120);
  Px = Py = 0;
}
//鼠标绝对移动
void Move_To(int16_t x,int16_t y)
{
	x -= Px;
  y -= Py;
	if(x > 0){while(x >= 100)x -= 100,Move(100,0);}
	else {while (x <= -100)x += 100,Move(-100,0);}
	Move(x,0);

	if(y > 0){while(y >= 100)y -= 100,Move(0,100);}
	else {while(y <= -100)y += 100,Move(0,-100);}
	Move(0,y);
}
//单击左键
void Click_L(void)
{
	Set_Mouse(0,0,0,1,0,0);
	Set_Mouse(0,0,0,0,0,0);
}
//单击右键
void Click_R(void)
{
	Set_Mouse(0,0,0,0,1,0);
	Set_Mouse(0,0,0,0,0,0);
}
//单击中键
void Click_M(void)
{
	Set_Mouse(0,0,0,0,0,1);
	Set_Mouse(0,0,0,0,0,0);
}
//移动到指定位置单击左键
void Move_To_Click(int16_t x,int16_t y)
{
	Move_To(x,y);
	Click_L();
}

添加自动化程序,需要将手机开发者选项打开,显示指针位置,方便确定每个步骤点击屏幕的具体位置。本文使用的安卓手机屏幕分辨率为1080x1920.
手机解锁程序:滑动解锁

移动到中下位置
按下左键
向上移动
松开左键
void Unlock(void)
{
	Move_To_Click(550,1890);//点击主页 为了防止已经解锁后乱点
	HAL_Delay(1000);//等待1s
	Move_To(600,1400);//移动到中下位置
	Set_Mouse(0,0,0,1,0,0);//按下左键
	Move_To(600,1000);//向上移动
	Set_Mouse(0,0,0,0,0,0);//松开左键
}

打开微信
先将微信图标放在桌面第2页特定位置,方便点击

移动到中下位置
滚轮翻页
点击微信图标
void Open_Wechat(void)
{
	Move_To_Click(550,1890);//主页
	HAL_Delay(1000);//等待1s
	Move_To(550,1000);//移动到中下某位置
	Scroll(-100);//翻页
	Move_To_Click(150,150);//点击微信图标
	HAL_Delay(1000);//等待1s
	Move_To_Click(400,1740);//点击微信通讯录
}

选择联系人
先将微信中联系人的备注添加前缀,这样就能进行排序。本文将常用的10个联系人备注分别加上 A0、A1、A2、A3、A4、A5、A6、A7、A8、A9。这样就可以精确定位联系人了。

回到微信主页
点击通讯录
点击字母A
点击A分组下的联系人
void Choose_Name(int8_t num)
{
	//点击5次返回图标,确保当前页面为微信主页,为了防止程序在微信中点错
	Move_To_Click(40,100);
	Move_To_Click(40,100);
	Move_To_Click(40,100);
	Move_To_Click(40,100);
	Move_To_Click(40,100);
	Move_To_Click(400,1740);//点击通讯录
	HAL_Delay(1000);//等待1s
	Move_To_Click(1050,410);//点击A
	HAL_Delay(1000);//等待1s
	Move_To_Click(200,num*133+350);//点击联系人名字 A0是350 A9是1550 均分1200/9=133
}

开始呼叫
这一步较简单。

点击音视频通话
点击视频通话
void Start_Call()
{
	Move_To_Click(550,1400);//点击音视频通话
	HAL_Delay(2000);//等待1s
	Move_To_Click(550,1460);//点击视频通话
} 

结束通话

void Stop_Call(void)
{
	Move_To_Click(550,1600);//挂电话 通话时会自动隐藏挂机按钮,这里点击后能显示按钮
	HAL_Delay(1000);//等待1s
	Move_To_Click(550,1600);//挂电话 通话时点击中间能挂电话
	Move_To_Click(350,1600);//挂电话 呼叫时点击左边能挂电话
}
/* USER CODE END 1 */

2.2 修改usb_device.h文件

对以上函数添加声明

/* USER CODE BEGIN FD */
void Set_Mouse(int8_t x,int8_t y,int8_t z,uint8_t L,uint8_t R,uint8_t M);
void Scroll(int8_t z);
void Move(int8_t x,int8_t y);
void Move_Reset(void);
void Move_To(int16_t x,int16_t y);
void Click_L(void);
void Click_R(void);
void Click_M(void);
void Move_To_Click(int16_t x,int16_t y);

void Unlock(void);
void Open_Wechat(void);
void Start_Call(void);
void Choose_Name(int8_t num);
void Stop_Call(void);

/* USER CODE END FD */

3 修改main.c文件

添加矩阵键盘扫描函数

/* USER CODE BEGIN 4 */
uint8_t Key_Scan(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	//前4个端口输出低电平
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_RESET);
	
	//前4个端口推挽输出
	GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	//后4个端口上拉输入
	GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_Delay(10);
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)==GPIO_PIN_RESET)//读取第1行
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
		//后4个端口推挽输出
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		//前4个端口上拉输入
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		HAL_Delay(10);
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET)return 'A';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_RESET)return '3';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)==GPIO_PIN_RESET)return '2';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)return '1';
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)==GPIO_PIN_RESET)//读取第2行
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
		//后4个端口推挽输出
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		//前4个端口上拉输入
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		HAL_Delay(10);
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET)return 'B';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_RESET)return '6';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)==GPIO_PIN_RESET)return '5';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)return '4';
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)==GPIO_PIN_RESET)//读取第3行
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
		//后4个端口推挽输出
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		//前4个端口上拉输入
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		HAL_Delay(10);
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET)return 'C';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_RESET)return '9';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)==GPIO_PIN_RESET)return '8';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)return '7';
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)==GPIO_PIN_RESET)//读取第4行
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
		//后4个端口推挽输出
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		//前4个端口上拉输入
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		HAL_Delay(10);
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==GPIO_PIN_RESET)return 'D';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_RESET)return '#';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)==GPIO_PIN_RESET)return '0';
		if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==GPIO_PIN_RESET)return '*';
	}
	return 0;
}

添加USB OTG功能切换函数

static void USB_OTG_ON(void)//开启OTG功能
{
	USB_OTG_FLAG = 1;
	HAL_GPIO_WritePin(USB_ID_GPIO_Port, USB_ID_Pin, GPIO_PIN_SET);
	HAL_Delay(100);
	HAL_GPIO_WritePin(GPIOA,USB_VCC_Pin, GPIO_PIN_RESET);
	HAL_Delay(1000);
	HAL_GPIO_WritePin(USB_ID_GPIO_Port, USB_ID_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,USB_VCC_Pin, GPIO_PIN_SET);
	HAL_Delay(1000);
	Move_Reset();
}

static void USB_OTG_OFF(void)//关闭OTG功能
{
	USB_OTG_FLAG = 0;
	HAL_GPIO_WritePin(USB_ID_GPIO_Port, USB_ID_Pin, GPIO_PIN_SET);
	HAL_Delay(100);
	HAL_GPIO_WritePin(GPIOA,USB_VCC_Pin, GPIO_PIN_RESET);
	HAL_Delay(1000);
	HAL_GPIO_WritePin(USB_ID_GPIO_Port, USB_ID_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA,USB_VCC_Pin, GPIO_PIN_SET);
}

/* USER CODE END 4 */

声明USB OTG状态标志位变量

/* USER CODE BEGIN PV */
static uint8_t USB_OTG_FLAG=0; 
/* USER CODE END PV */

声明以上三个函数

/* USER CODE BEGIN PFP */
static void USB_OTG_ON(void);
static void USB_OTG_OFF(void);
uint8_t Key_Scan(void);
/* USER CODE END PFP */

编写主函数程序


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
	/* USER CODE BEGIN 1 */
	uint8_t key;
	uint16_t timeout_10ms;
	/* 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_USB_DEVICE_Init();
	/* USER CODE BEGIN 2 */
	USB_OTG_OFF();
	/* USER CODE END 2 */
	
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while(1)
	{ 
    /* USER CODE END WHILE */
		key = Key_Scan();
		if(key)
		{
			if(USB_OTG_FLAG==0)USB_OTG_ON(),timeout_10ms=6000;//60s未操作关闭OTG,进行手机充电
			switch(key)
			{
				case 'A':Unlock();		break;
				case 'B':Open_Wechat();	break;
				case 'C':Start_Call();	break;
				case 'D':Stop_Call();	break;
				case '0':Choose_Name(0);break;
				case '1':Choose_Name(1);break;
				case '2':Choose_Name(2);break;
				case '3':Choose_Name(3);break;
				case '4':Choose_Name(4);break;
				case '5':Choose_Name(5);break;
				case '6':Choose_Name(6);break;
				case '7':Choose_Name(7);break;
				case '8':Choose_Name(8);break;
				case '9':Choose_Name(9);break;
				case '*':Unlock();HAL_Delay(1000);Open_Wechat();break;
				case '#':Start_Call();break;
			}
		}
		if(USB_OTG_FLAG){if(timeout_10ms--)HAL_Delay(10);else USB_OTG_OFF();} 		
    /* USER CODE BEGIN 3 */
	}
  /* USER CODE END 3 */
}

四、结语

可编程鼠标的应用范围远不止此,还有许多实用场景,比如电视盒子一键收看节目、代替手机脚本完成自动化操作,将手机作为小电视一键收看等等,整个制作流程并不复杂,却开了先河。如有错误望批评指正,因春运期间快递停运没有接插件,只能焊接,外观不佳。更多场景和功能等待各位开发者们探索。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 11:11:54  更:2022-02-04 11:13:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/5 9:12:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码