STM32库函数开发系列文章目录

第一篇:STM32F103ZET6单片机双串口互发程序设计与实现
第二篇:最简单DIY基于STM32单片机的蓝牙智能小车设计方案
第三篇:最简单DIY基于STM32F407探索者开发板的MPU6050陀螺仪姿态控制舵机程序
第四篇:最简单DIY基于STM32F407探索者开发板和PCA9685舵机控制模块的红外遥控机械臂控制程序
第五篇:注释最详细、代码最简单的STM32+摄像头+显示屏的颜色跟踪电路软硬件方案
第六篇:最简单DIY基于STM32单片机的WIFI智能小车设计方案
第七篇:最简单DIY基于STM32的远程控制电脑系统①(电容触摸+按键控制)
第八篇:最简单DIY基于STM32的远程控制电脑系统②(无线遥杆+按键控制)



前言

    daodanjishui物联网核心原创技术之最简单DIY基于STM32的远程控制电脑系统②(无线遥杆+按键控制)。
    市面上有各种开源电脑控制软件和硬件的方案,但是有复杂的有简单的,如果想快速入门STM32控制电脑的软硬件方案,这个方案会给你一个快捷高效的方案。


一、最简单DIY基于STM32的远程控制电脑系统②(无线遥杆+按键控制)是什么?

    我记得本栏的第七篇博文:**最简单DIY基于STM32的远程控制电脑系统①(电容触摸+按键控制)**的设计中大量使用了库函数和别人的开源代码,鲁迅先生的“拿来主义”表现的淋漓尽致,这也是STM32库函数开发的魅力所在,完成了触摸屏和按键控制电脑鼠标。为了实现STM32无线+遥杆控制电脑,所以诞生第八篇博文。
    由于使用STM32单片机与电脑形成有线连接去控制电脑,有点不方便,所以在第八篇中,将推出用无线模块NRF24L01进行无线通信,说白了就是:制作无线鼠标,所以需要用到两块STM32开发板和NRF24L01模块,上位机采用正点原子战舰开发板通过USB数据线与笔记本电脑相连,下位机是德飞莱迷你stm32开发板通过NRF24L01无线模块与上位机进行无线连接。
     由于国内电脑远程控制技术封锁,一些技术和理论都是本人经过摸索实践推敲得出,没有权威性,所以仅供参考。首先要谈到用软件和硬件控制电脑的方案:软件有socket编程和java 鼠标键盘控制sdk开发,硬件有单片机USB鼠标键盘库的使用。下面先介绍ST公司STM32F103ZET6自带的鼠标控制电脑的方案。用到的是正点原子战舰开发板和配套的4.3寸电容触摸屏。最终实现用单片机的触摸屏实现鼠标控制的效果。全家福如下图所示:
在这里插入图片描述
无线模块在每个开发板的左上角,热拔插结构。遥杆模块是用杜邦线连接在德飞莱迷你STM32F103ZET6开发板上的。大的单片机是正点原子战舰开发板。小单片机是用蓝色小充电宝供电,大单片机用电脑USB数据线供电。

B站视频演示地址:https://www.bilibili.com/video/BV1MU4y117aq?t=0.0

视频如下

最简单DIY基于STM32的远程控制电脑系统②(无线摇杆+按键控制)


二、拿来主义日记

1.准备硬件和接线

     硬件需要正点原子开发板和4.3寸配套的电容触摸屏,无线模块在每个开发板的左上角,热拔插结构。遥杆模块是用杜邦线连接在德飞莱迷你STM32F103ZET6开发板上的。大的单片机是正点原子战舰开发板。小单片机是用蓝色小充电宝供电,大单片机用电脑USB数据线供电。由于用到了正点原子的开源代码进行人工二次合成,所以这个方案全部免费,后期我有更猛的代码,可以实现更高级的控制效果,当然后期可能需要收费。后期能做到空中鼠标控制,控制遥杆控制,空中手机控制,控制MPU6050控制, 远程MQTT控制等等。

代码预览截图如下(上位机鼠标发射端代码截图):
在这里插入图片描述

代码预览截图如下(下位机电脑接收端代码截图):
在这里插入图片描述

2.技术点说明

    从视频可以看出,可以灵活使用无线遥杆来控制笔记本电脑的鼠标进行上下左右对角线移动。代码是核心原创的,包括的知识点有:STM32字库编程、STM32电容屏触摸控制和显示、STM32 USB开发、SPI通信技术、NRF24L01无线模块的使用和私人定义无线通信协议的传输和解析、STM32 两路ADC遥杆参数采集、按键电平检测技术、电容屏彩色字体显示、显示屏涂鸦显示和清屏技术等等。
    刚开始调试的时候由于遥杆采集的ADC数据不稳定导致鼠标漂移,后面我采用了有效的方案锁定住鼠标,效果非常不错,所以才有勇气把如此珍贵丝滑的代码分享给大家。有了这套代码,读者可以开发有关电脑鼠标原创控制的项目,下一期我会以ESP8266 AT 固件的方式 和 Arduino SDK二次开发的方式 与STM32单片机构成手机客户端遥控电脑的方案。daodanjishui原创经典值得期待。

3.资料展示和源码展示

    文末尾有下载资料的地址。资料列表如下所示:
在这里插入图片描述

源码如下:(移植了ST公司控制电脑鼠标的库,发射机(无线鼠标))

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"  
#include "24cxx.h" 
#include "I2C.h"
#include "touch.h" 
#include "usb_lib.h"
#include "hw_config.h"
#include "usb_pwr.h" 
#include "string.h"
#include "mpu6050.h"
#include "spi.h"
#include "24l01.h"
#include "malloc.h"
#include "sdio_sdcard.h"  
#include "w25qxx.h"    
#include "ff.h"  
#include "exfuns.h"   
#include "text.h"		
#include "usart3.h"
#include "fontupd.h" 
#include "adc.h"
/************************************************
 实验0:ALIENTEK STM32F103开发板工程模板
 注意,这是手册中的调试章节使用的main文件
 技术支持:daodanjishui 2022.5.16
 CSDN博客:https://blog.csdn.net/niruxi0401 
 作者:daodanjishui
************************************************/
//ALIENTEK Mini STM32开发板范例代码21  二次开发为战舰4.3寸电容屏鼠标触控板
//触摸屏实验  
//技术支持:daodanjishui  	2022.5.16
//增加一个单片机作为遥控器,原来单片机作为接收机
//两个NRF24L01无线模块使用SPI总线控制,分别安装在遥控器和接收机上
//这个代码是单片机遥控代码:鼠标
//加入ADC遥杆控制鼠标 2022.5.29
//遥杆控制鼠标上下左右,遥杆按下是鼠标点击

//计算 x1,x2 的绝对值
u32 usb_abs(u32 x1,u32 x2)
{
if(x1>x2)return x1-x2;
else return x2-x1;
}
int main(void)
{ 
//short temp[3];//存放mpu6050数据的数组
//u8 tmp_buf[33];	 //发射寄存器
u8 tmp_buf[33]="The mouse is connection!";
u8 key;
short X=0,Y=0;		 //发送到电脑端的坐标值
u8 keysta=0;
short rollsta=0;  
int i;
//遥杆供电为板载3.3的电压
	
#define GO_speed_p 15     //这个是鼠标移动跨度的灵敏度,可以从0~60的数值进行调整
//#define BACK_speed_p 60
//#define LEFT_speed_p 60
#define RIGHT_speed_p 15
	
	
float go_mid = 1.62;    //全局变量获取最初静止状态游戏手柄y中位电压值
int go_speed = 0;
//int back_speed = 0;
float turn_mid = 1.69;    //全局变量获取最初静止状态游戏手柄x中位电压值
//int left_speed = 0;
int right_speed = 0;
	
      u16 adcx1;
      u16 adcx2;
      //u16 temp3;
      //u16 temp4;
      float temp1;    //浮点型
      float temp2;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组设置 
delay_init();  //延时初始化
uart_init(115200); //串口 1 初始化
//LCD_Init();  //初始化液晶
LED_Init(); //LED 初始化
KEY_Init();  //按键初始化
//TP_Init();  //初始化触摸屏 
MYI2C_Init();//I2C初始化
MPU6050_Init();//陀螺仪初始化
//W25QXX_Init();				//初始化W25Q128
usart3_init(115200);		//初始化串口3 
//my_mem_init(SRAMIN);		//初始化内部内存池
//exfuns_init();				//为fatfs相关变量申请内存  
//f_mount(fs[0],"0:",1); 		//挂载SD卡 
//f_mount(fs[1],"1:",1); 		//挂载FLASH.
delay_ms(40);
Adc_Init();
NRF24L01_Init();//24l01初始化
	 		while(NRF24L01_Check())	//检测无线模块能否用,否则死循环
		{
				printf("未检测到24l01\r\n");
				delay_ms(200);
			//无线模块不能用的测试
		}
     NRF24L01_TX_Mode();//设置24l01为发射模式
	//NRF24L01_RX_Mode();//设置24l01为接收模式	
	NRF24L01_TxPacket(tmp_buf);//发送链接成功的字符串	
  while(1)
  {		 		
		key=KEY_Scan(1);
		if(key==WKUP_PRES)			//WK_UP 退出测试		 
		{ 
			printf("WKUP_PRES");	
       rollsta=1;//滚轮向上	
			
		}
		else if(key==KEY0_PRES)	//KEY0 向ID0发送数据 
		{   
       printf("KEY0_PRES"); 
			 keysta|=0X02;					//发送鼠标右键		 
		}
		else if(key==KEY1_PRES)	//KEY1 向ID1发送数据 
		{
			  printf("KEY1_PRES");
			  rollsta=-1;
		    //发送滚轮数据到电脑 向下			
		}else if(key==KEY2_PRES){
			 printf("KEY2_PRES");
			 keysta|=0X01;					//发送鼠标左键 
			
		}else if(keysta||rollsta!=0)//之前有按下
		{
			keysta=0; //发送松开命令给电脑
			rollsta=0;
		}
		

	 adcx1=Get_Adc_Average(ADC_Channel_1,10);//通道1采集,采集十个数取平均值,连接PA1
   temp1=(float)adcx1*(3.3/4096);//12位的最大值是4096
		if(go_mid-temp1>=0.3)//鼠标后退,这个比较值需要调整一下,免得遥杆静止的时候乱飘
        go_speed =(go_mid-temp1)*GO_speed_p;//将电压值转为鼠标的位移
      else
        go_speed = (go_mid-temp1)*GO_speed_p;
		
		if(usb_abs(go_mid,temp1)>0.3)//防止遥杆静止的时候发生小数据变化	
      Y=go_speed;
		else
			Y=0;
    
   adcx2=Get_Adc_Average(ADC_Channel_2,10);//通道2采集,取十个数值的平均值,接PA2
   temp2=(float)adcx2*(3.3/4096);//12位的最大值是4096
    if(turn_mid-temp2>=0.3)//鼠标左转
        right_speed =(turn_mid-temp2)*RIGHT_speed_p;//将电压值转为鼠标的位移
      else
        right_speed =(turn_mid-temp2)*RIGHT_speed_p;
			
			
		if(usb_abs(turn_mid,temp2)>0.3)		
			X=right_speed;
    else
		  X=0;
		
			
				tmp_buf[0]=(u8)keysta;
				tmp_buf[1]=(u8)((X>>8)&0x00ff);
				tmp_buf[2]=(u8)(X&0x00ff);
				tmp_buf[3]=(u8)((Y>>8)&0x00ff);
				tmp_buf[4]=(u8)(Y&0x00ff);
				tmp_buf[5]=(u8)rollsta;
					key=' ';
			  for(i=6;i<32;i++){
					key++;
					if(key>('~'))key=' ';
					tmp_buf[i]=key;
				}
	
			  tmp_buf[32]=0;
		    printf("X=%d,Y=%d\n",X,Y);
		
		if(NRF24L01_TxPacket(tmp_buf)==TX_OK){
				int i;
				for(i=0;i<32;i++){
				  tmp_buf[i]=0;//清空数组
				}	
			  LED1=0;//德飞莱开发板的LED2发亮
		}	else   LED1=1;//德飞莱开发板的LED2不亮
	}
} 

接收机源码:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "key.h"  
#include "24cxx.h" 
#include "touch.h" 
#include "usb_lib.h"
#include "hw_config.h"
#include "usb_pwr.h" 
#include "string.h"
#include "spi.h"
#include "24l01.h"
#include "malloc.h"
#include "sdio_sdcard.h"  
#include "w25qxx.h"    
#include "ff.h"  
#include "exfuns.h"   
#include "text.h"		
#include "usart3.h"
#include "fontupd.h" 
#include "math.h"
/************************************************
 实验0:ALIENTEK STM32F103开发板工程模板
 注意,这是手册中的调试章节使用的main文件
 技术支持:daodanjishui 2022.5.16
 CSDN博客:https://blog.csdn.net/niruxi0401 
 作者:daodanjishui
************************************************/
//ALIENTEK Mini STM32开发板范例代码21  二次开发为战舰4.3寸电容屏鼠标触控板
//触摸屏实验  
//技术支持:daodanjishui  	2022.5.16
//增加一个单片机作为遥控器,原来单片机作为接收机
//两个NRF24L01无线模块使用SPI总线控制,分别安装在遥控器和接收机上
//一个正点原子的MPU6050陀螺仪模块使用IIC总线控制,安装在遥控单片机上
//这个接收机的代码优势在于可以通用于:体感+按键鼠标   和  遥杆+按键鼠标 

//装载画图界面 
void Load_Draw_Dialog(void)
{
LCD_Clear(WHITE);//清屏
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(lcddev.width-24,0,200,16,16,"RST");//显示清屏区域
POINT_COLOR=RED;//设置画笔蓝色
} 
//计算 x1,x2 的绝对值
u32 usb_abs(u32 x1,u32 x2)
{
if(x1>x2)return x1-x2;
else return x2-x1;
}
int main(void)
{ 
u8 tmp_buf[33];
u8 key;
short X=0,Y=0;		 //发送到电脑端的坐标值
s8 x0,y0; //发送到电脑端的坐标值
u8 keysta=0; 
//[0]:0,左键松开;1,左键按下;
//[1]:0,右键松开;1,右键按下
//[2]:0,中键松开;1,中键按下
u8 tpsta=0;  //0,触摸屏第一次按下;1,触摸屏滑动
int xlast, ylast; //最后一次按下的坐标值
u8 *p;//发送命令的指针
int i;
u16 t=999;		//加速第一次获取链接状态
u8 timex;	//设置循环次数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组设置 
delay_init();  //延时初始化
uart_init(115200); //串口 1 初始化
LCD_Init();  //初始化液晶
LED_Init(); //LED 初始化
KEY_Init();  //按键初始化
TP_Init();  //初始化触摸屏 
//W25QXX_Init();				//初始化W25Q128
usart3_init(115200);		//初始化串口3 
my_mem_init(SRAMIN);		//初始化内部内存池
//exfuns_init();				//为fatfs相关变量申请内存  
//f_mount(fs[0],"0:",1); 		//挂载SD卡 
//f_mount(fs[1],"1:",1); 		//挂载FLASH.
delay_ms(40);
font_init();			//检查字库是否OK
NRF24L01_Init();//24l01初始化
	 		while(NRF24L01_Check())	//检测无线模块能否用,否则死循环
		{
				printf("未检测到24l01\r\n");
				delay_ms(200);
			//无线模块不能用的测试
			POINT_COLOR=RED;
      LCD_ShowString(60,50,200,16,16,"24l01 can not open");
		}
	
//NRF24L01_TX_Mode();//设置24l01为发射模式
//NRF24L01_RX_Mode();//设置24l01为接收模式
POINT_COLOR=RED;
LCD_ShowString(60,50,200,16,16,"战舰 STM32");
LCD_ShowString(60,70,200,16,16,"USB Mouse TEST");
LCD_ShowString(60,90,200,16,16,"daodanjishui");
LCD_ShowString(60,110,200,16,16,"2022.5.16"); 
LCD_ShowString(60,130,200,16,16,"KEY_UP:SCROLL +  KEY_DOWN:SCROLL -");
//LCD_ShowString(60,130,200,16,16,"KEY_DOWN:SCROLL -");
LCD_ShowString(60,150,200,16,16,"KEY1:RIGHT Button"); 
LCD_ShowString(60,170,200,16,16,"KEY0:LEFT Button");
delay_ms(1800);
USB_Port_Set(0); //USB 先断开
delay_ms(300);
USB_Port_Set(1); //USB 再次连接
USB_Interrupts_Config(); //USB 中断配置
Set_USBClock(); //USB 时钟设置
USB_Init();  //USB 初始化		
Load_Draw_Dialog();

  while(1)
  {		 
		   
		   NRF24L01_RX_Mode();		  		    		    				 
			if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来.
			{
				tmp_buf[32]=0;//加入字符串结束符 
        Show_Str(15,155,180,190,tmp_buf,12,0);//显示接收到的数据 
				X=(s16)((tmp_buf[1]<<8)|tmp_buf[2]);
			  Y=(s16)((tmp_buf[3]<<8)|tmp_buf[4]);	
			  printf("Button=%d,X=%8d,Y=%8d,SCROLL=%d\r\n",tmp_buf[0],X,Y,tmp_buf[5]);//在串口一打印NRF24L01传输过来的参数	
			  Joystick_Send(tmp_buf[0],X,Y,tmp_buf[5]);				
				for(i=0;i<32;i++){
				  tmp_buf[i]=0;//清空数组
				}
				 
			}				    
	
	    key=KEY_Scan(0);//按键扫描	
		if(key==WKUP_PRES)			//WK_UP 退出测试		 
		{ 
			printf("WKUP_PRES");	
      LCD_ShowString(60,130,200,16,16,"KEY_UP:SCROLL +");			
       //rollsta=1;//滚轮向上		
       Joystick_Send(0,0,0,1);	
       u3_printf("WKUP_PRES\r\n");			
		}
		else if(key==KEY0_PRES)	//KEY0 向ID0发送数据 
		{   
     printf("KEY0_PRES");
		  keysta|=0X02;					//发送鼠标右键	
	    LCD_ShowString(60,130,200,16,16,"KEY1:RIGHT Button");
			Joystick_Send(2,0,0,0);
		}
		else if(key==KEY1_PRES)	//KEY1 向ID1发送数据 
		{ 
			  printf("KEY1_PRES");
        LCD_ShowString(60,130,200,16,16,"KEY_DOWN:SCROLL -");
			  //rollsta=-1;
		    //发送滚轮数据到电脑  向下	
        Joystick_Send(0,0,0,(u8)-1);		
    
			
		}else if(key==KEY2_PRES){
			 printf("KEY2_PRES");
			 keysta|=0X01;					//发送鼠标左键 	
       Joystick_Send(1,0,0,0);	
       LCD_ShowString(60,130,200,16,16,"KEY0:LEFT Button");
  
			
		}else if(keysta)//之前有按下
		{
			keysta=0; //发送松开命令给电脑
			Joystick_Send(0,0,0,0);
		}
    		 		 
			    tp_dev.scan(0); //触摸屏扫描
			   if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下
        {
				 //最少移动 5 个单位,才算滑动
					if(((usb_abs(tp_dev.x[0],xlast)>4)||(usb_abs(tp_dev.y[0],ylast)>4))&&tpsta==0)
					{
					 xlast=tp_dev.x[0]; //记录刚按下的坐标
					 ylast=tp_dev.y[0];
					 tpsta=1;
					 }
					if(tp_dev.x[0]<lcddev.width&&tp_dev.y[0]<lcddev.height)
					{ 
					 if(tp_dev.x[0]>(lcddev.width-24)&&tp_dev.y[0]<16)Load_Draw_Dialog();
						 else{ 
							 TP_Draw_Big_Point(tp_dev.x[0],tp_dev.y[0],RED);  //画图 
						 }
					 if(bDeviceState==CONFIGURED)
						{
										 if(tpsta)//滑动
										{
											x0=(xlast-tp_dev.x[0])*3;//上次坐标与得到的坐标之差,扩大 2倍
											y0=(ylast-tp_dev.y[0])*3;
											xlast=tp_dev.x[0]; //记录刚按下的坐标
											ylast=tp_dev.y[0];
											Joystick_Send(keysta,-x0,-y0,0); //发送数据到电脑
											delay_ms(5);
										}
						 } 
					}
         }else { tpsta=0;delay_ms(1); }//清除	
				
        if(bDeviceState==CONFIGURED)
				 LED1=0;//USB配置成功,则绿灯亮
          else 
         LED1=1;
				 

		    if(timex)timex--;
 	      if(timex==1)LCD_Fill(30+54,125,239,122,WHITE);//清屏
	      t++;
	      delay_ms(10); //10毫秒
	    if(t==1000)				 
		      t=0;
	     if((t%20)==0)LED0=!LED0;
			myfree(SRAMIN,p);		//释放内存	
     }

    	
			
		 
} 

三、运行与调试

请看录制好的视频演示。


四、总结

    总结:通过STM32单片机使用USB数据与电脑相连,不需要安装电脑驱动就可以用单片机控制电脑的鼠标,触摸屏和按键都可以同时控制鼠标的操作,程序设计精妙,拿来主义表现良好。这篇博文保留上述功能之外加入了无线遥杆控制和按键遥控,代码真的精简规范,非常适合二次开发和学习。这一篇的内容是接上一篇:《最简单DIY基于STM32的远程控制电脑系统①(电容触摸+按键控制)》,所以部分免费的资料请到上篇博文(第七篇)去下载。

    后期会推出体感遥控器的开源软硬件的方案,daodanjishui嵌入式核心技术值得期待。请认准我的品牌,不断更新和创新是我的特色。追求原创开源是我的宗旨。具体硬件和软件资料比较多,请读者打包下载才能快速掌握这套源码。

最后附上本博文代码下载地址:https://gf.bilibili.com/item/detail/1107812114
直接跳转

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐