Implementing buttons on STM32F103ZET6

Last time we have made a good starting point with setting up a project template for the STM32F103ZET6 development board using GNU tools. Using the same project template, we can move forward and start programming other elements. This time a quick note about adding a button library. This is a modest implementation that initializes port pins and then reads their status.

buttons on STM32F103ZET6

The Development board is equipped with four user-programmable buttons named WAKEUP, TAMPER, USER1, and USER2. We will not care about the meaning of names; use them as general-purpose buttons for now.

For this, we need to create another pair of driver files buttons.c and buttons.h. In buttons.h file, we define button ports and pins with some friendly names. Also as well we have to think about clocking proper peripheral buses.

#define BWAKEUP 			GPIO_Pin_0
#define BWAKEUPPORT			GPIOA
#define BWAKEUPPORTCLK		RCC_APB2Periph_GPIOA
#define BTAMPER 			GPIO_Pin_13
#define BTAMPERPORT			GPIOC
#define BTAMPERPORTCLK		RCC_APB2Periph_GPIOC
#define BUSER1 				GPIO_Pin_8
#define BUSER1PORT			GPIOA
#define BUSER1PORTCLK		RCC_APB2Periph_GPIOA
#define BUSER2 				GPIO_Pin_3
#define BUSER2PORT			GPIOD
#define BUSER2PORTCLK		RCC_APB2Periph_GPIOD

Next step is button initialization. In buttons.c we create a function:

void ButtonsInit(void)
{
  //GPIO structure used to initialize Button pins
  GPIO_InitTypeDef GPIO_InitStructure;
  //Enable clock on APB2 pripheral bus where buttons are connected
  RCC_APB2PeriphClockCmd(BWAKEUPPORTCLK|BTAMPERPORTCLK|BUSER1PORTCLK|BUSER2PORTCLK,  ENABLE);
  //select pins to initialize WAKEUP and USER1 buttons
  GPIO_InitStructure.GPIO_Pin = BWAKEUP|BUSER1;
  //select floating input mode
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  //select GPIO speed
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(BWAKEUPPORT, &GPIO_InitStructure);
  //select pins to initialize TAMPER button
  GPIO_InitStructure.GPIO_Pin = BTAMPER;
  GPIO_Init(BTAMPERPORT, &GPIO_InitStructure);
  //select pins to initialize USER2 button
  GPIO_InitStructure.GPIO_Pin = BUSER2;
  GPIO_Init(BUSER2PORT, &GPIO_InitStructure);
}

Here we have to enable peripheral clocks for used ports with the RCC_APB2PeriphClockCmd command. Then we can start setting up port pins. According to the peripheral library, we need to do this through the structure variable where each field carries a particular setting. These would be GPIO_Pins (all pins set for the same port), then GPIO_Mode – we set it as input floating, and GPIO_Speed as max. Buttons aren’t connected to the same port, so we have to do initialization separately for each port with the GPIO_Init function.

Lastly, we write a simple function that reads a button state.

uint32_t ButtonRead(GPIO_TypeDef* Button_Port, uint16_t Button)
{
  return !GPIO_ReadInputDataBit(Button_Port, Button);
}

When pressed, buttons pulls port pin low so GPIO_ReadInputDataBit() function returns ‘0’. Probably it is more logical to have ‘1’ on click, so we used the NOT ‘!’ operator to do so. And here is a simple demo code that lights the different LEDs on each button press. Code still runs in a super loop, so don’t judge code efficiency; it’s only for demonstration.

//Buttons Test
#include "stm32f10x.h"
#include "leds.h"
#include "buttons.h"
//delay function
void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}
int main(void)
{
  //init leds
  LEDsInit();
  ButtonsInit();
while (1)
  {
	//read Wakeup button
	if (ButtonRead(BWAKEUPPORT, BWAKEUP))
	{
		//led 1 on
		LEDOn(1);
		//delay
		Delay(500000);
		//led 1 off
		LEDOff(1);
	}
	//read TAMPER button
	if (ButtonRead(BTAMPERPORT, BTAMPER))
	{
		//led 2 on
		LEDOn(2);
		//delay
		Delay(500000);
		//led 2 off
		LEDOff(2);
	}
	//read User1 button
	if (ButtonRead(BUSER1PORT, BUSER1))
	{
		//led 3 on
		LEDOn(3);
		//delay
		Delay(500000);
		//led 3 off
		LEDOff(3);
	}
	//read User2 button
	if (ButtonRead(BUSER2PORT, BUSER2))
	{
		//led 4 on
		LEDOn(4);
		//delay
		Delay(500000);
		//led 4 off
		LEDOff(4);
	}
  }
}

In real applications buttons, a check should be interrupt based. But we will get to that soon.

Project source code[420KB]

Leave a Reply