Emulate STM32F103 as a MOUSE

This is another tutorial in the USB Series of STM32, and today we will see how to use STM32F103C8 as a mouse. This is not limited to F103C8, you can use any other STM32 Device, which have the user USB port available. Basically this tutorial is an example of USB HID DEVICE.

I will be using the ADXL345 accelerometer sensor to get the acceleration in x and y axis, and based on these acceleration values the mouse will move. I am going to attach one button on the breadboard, so that we can get the left click functionality. You can attach one more button for the right click if you want to. You can see the connections below

CubeMX Setup

I am creating this project in CubeIDE, and the following is the setup required in CubeMX


USB setup

In the picture above, I have selected the USB Device HID class. Everything else is kept default.

I2C Setup for ADXL345

i2c setup

I2C1 is selected for ADXL345, and rest is default setup

EXTI Setup


I have selected Pin PA7 for the button, and so using external interrupt here. Button is also connected to 3.3V supply, and that’s why I am using a pull down here.

Some Insight into the code


#define ADXL_ADDRESS 0x53<<1

uint8_t Rx_Data[6];

int16_t x,y,z;

void Adxl_Write (uint8_t reg, uint8_t value)
	uint8_t data[2];
	data[0] = reg;
	data[1] = value;
	HAL_I2C_Master_Transmit (&hi2c1, ADXL_ADDRESS, data, 2, 100);

void Adxl_Read (uint8_t reg)
	HAL_I2C_Mem_Read (&hi2c1, ADXL_ADDRESS, reg, 1, (uint8_t *)Rx_Data, 6, 100);

void Adxl_Init (void)
	Adxl_Write (0x31, 0x01);  // data_format range= +- 4g
	Adxl_Write (0x2d, 0x00);  // reset all bits
	Adxl_Write (0x2d, 0x08);  // power_cntl measure and wake up 8hz


Above are the ADXL related functions, and i have already covered them before. You can read more about them here

void Adxl_Calibrate (void)
	for (int i=0; i<50; i++)
		Adxl_Read (0x32);
		x = ((Rx_Data[1]<<8)|Rx_Data[0]);
		y = ((Rx_Data[3]<<8)|Rx_Data[2]);
		z = ((Rx_Data[5]<<8)|Rx_Data[4]);
		min_xval = MIN(min_xval, x);
		max_xval = MAX(max_xval, x);
		min_yval = MIN(min_yval, y);
		max_yval = MAX(max_yval, y);
		HAL_Delay (100);

	/* Turn On the LED to show the completion of calibration */
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);

Calibration is needed so that we can use the mouse in different orientations. Basically it will sample 50 values in 5 seconds, and then set the max and the min values. Once the calibration is complete, the LED on BluePill will turn ON.


extern USBD_HandleTypeDef hUsbDeviceFS;

typedef struct
	uint8_t button;
	int8_t mouse_x;
	int8_t mouse_y;
	int8_t wheel;
} mouseHID;

mouseHID mousehid = {0,0,0,0};

I have created a structure here, to save the mouse parameters.


uint8_t button_flag=0;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
	if (GPIO_Pin == GPIO_PIN_7)
		button_flag = 1;

In the EXTI Callback function, we will just update the flag. The rest of this processing will be done in the while loop.

While Loop

Adxl_Read (0x32);
x = ((Rx_Data[1]<<8)|Rx_Data[0]);
y = ((Rx_Data[3]<<8)|Rx_Data[2]);
z = ((Rx_Data[5]<<8)|Rx_Data[4]);

if (x < min_xval)
   newxval = x - min_xval;

else if (x > max_xval)
   newxval = x - max_xval;

if (y < min_yval)
  newyval = y - min_yval;

else if (y > max_yval)
 newyval = y - max_yval;

if ((newxval > 20) || (newxval <-20))
 mousehid.mouse_y = (newxval/3);

else mousehid.mouse_y = 0;
if ((newyval > 20) || (newyval <-20))
 mousehid.mouse_x= (newyval)/3;

else mousehid.mouse_x = 0;
if (button_flag==1)
 mousehid.button = 1;
 USBD_HID_SendReport(&hUsbDeviceFS, &mousehid, sizeof (mousehid));
 HAL_Delay (50);
 mousehid.button = 0;

 USBD_HID_SendReport(&hUsbDeviceFS,&mousehid, sizeof (mousehid));
 button_flag =0;

USBD_HID_SendReport(&hUsbDeviceFS,&mousehid, sizeof (mousehid));


Here is our while loop
Basically we read the RAW acceleration values from the sensor and then do the processing

  • if the value is higher than the max value, or lower than the min value, we save it to the mouse structure
  • in the end we send this structure as a part of the HID report.
  • The sensitivity can be controlled by dividing the newval (newval/3). The higher the divisor, the less sensitive will be the mouse
  • if the button is clicked, we send the button =1 report, and 50 ms later button =0 report to indicate the release of the button.
  • you can modify this button to send button =2 for the right click.



Check out the Video Below


You can help with the development by DONATING OR Just click DOWNLOAD to download the code

Notify of

Oldest Most Voted
Inline Feedbacks
View all comments

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.