Implementation of ch0 CBsp class

Posted by JohnnyBlaze on Fri, 25 Feb 2022 01:46:10 +0100

Why use C + + to develop MCU program

In the embedded system with microprocessor as the core, most of them use C language for program design, but with the increase of system scale, the program is more and more complex and maintenance is more and more difficult. Using C + + for development has the following advantages (provided that the compiler must support c + +, otherwise it is empty talk):

  1. Reduced parameter passing. In C + +, the data used can be used as data members, which can avoid the parameter transfer process of the function and improve the execution speed and efficiency.
  2. Safer. C + + encapsulates data and methods, which can hide the details of class implementation and avoid the exposure of internal data structure.
  3. Can reduce naming conflicts. C language has no concept of namespace, which is easy to lead to name conflict.

Of course, in C language, the function pointer can also be defined in the structure to achieve the effect similar to C + + encapsulation. However, this method is troublesome, and there is no access control in C language. All members in the structure can be accessed directly, which is not conducive to hiding the details of the implementation. Moreover, if the caller is not familiar with the structure and accesses members that should not be accessed, the consequences are disastrous.

Here I take stm32l151c8t6 as an example to share with you how to use C + + for MCU development. The compiler uses MDK and the firmware library is stm32l1xx_ StdPeriph_ Lib_ V1. three point one

Viewing object-oriented programming style from running water lamp

The following are examples of process oriented and object-oriented programming styles:

Process oriented program style:

int main(){
	BSP_Init();
	while(1){
		delay(2000);
		GPIO_SetBits(LED1);
		delay(2000);
		GPIO_ResetBits(LED1);
	}
	return 0;
}

Object oriented program style:

int main(){
	CBsp  bsp;
	bsp.Init();
	CLed led1(LED1);
	while(1){
     bsp.delay_ms(2000);
		 led1.isOn()?led1.Off():led1.On();
	}
	return 0;
}

It can be seen that the idea of object-oriented program style is clearer. For the business code in while(1), if the underlying IO changes, the process oriented program modification involves the modification of business code. For the object-oriented program, only the relevant classes need to be modified without modifying the business code, which greatly reduces the maintenance cost of complex programs.

Moreover, due to the encapsulation of related functions and data into related classes, the program has better classification and hierarchy. Let me introduce our first class CBsp.

The first C + + class ---- CBsp

Functions of CBsp:

  1. Initialize the resources related to the system: such as setting the interrupt vector attribute and debugging the initialization of the serial port.

  2. Provide delay operation for users.

This is the CBsp class:

class CBsp{ 
public: 
    void Init(void); 
    void delay_us(uint32_t n_ms); 
    void delay_ms(uint16_t n_ms); 
private: 
    void sys_debug_Init(void); 
    void SysTick_Init(void); 
};

Specific implementation:

#include "Bsp.h"
#ifdef __GNUC__
   #define PUTCHAR_PROTOTYPE int __io_putchar (int ch)
#else
	 #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)
#endif
extern "C"
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART2, (uint8_t) ch);
  /* Loop until transmit data register is empty */
  while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
  {}
  return ch;
}

static uint8_t  fac_us=0;	//Delay multiplier			   
static uint16_t fac_ms=0;	//ms delay multiplier

void CBsp::Init(void){
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	sys_debug_Init();
  SysTick_Init();
}
/*
 *Configure systick as a 24Bit down counter for general delay purposes only
 *CPU Dominant frequency = 32MHz
 */
void CBsp::SysTick_Init(void)
{
	//uint32_t reload = 0;
	SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;//systick_clk = 4MHz
	fac_us = 4;//1us requires 4 systick clocks
	fac_ms = (uint16_t)fac_us*1000;
}

/*
	Maximum 4194304us
*/
void CBsp::delay_us(uint32_t n_us)
{
	uint32_t temp;	    	 
	SysTick->LOAD=n_us*fac_us; 			          //Time loading	  		 
	SysTick->VAL=0x00;        					      //Clear counter
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//Start counting down	  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		  //Waiting time arrives   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//Turn off counter
	SysTick->VAL =0X00;      					        //Clear counter	 
}
/*
  Maximum 4194ms
*/
void CBsp::delay_ms(uint16_t n_ms)
{	 		  	  
	uint32_t temp;		   
	SysTick->LOAD=(uint32_t)n_ms*fac_ms;			//Time loading (systick - > load is 24bit)
	SysTick->VAL =0x00;							          //Clear counter
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//Start counting down  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		  //Waiting time arrives   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//Turn off counter
	SysTick->VAL =0X00;       					      //Clear counter	  	    
} 

void CBsp::sys_debug_Init(void)
{
	GPIO_InitTypeDef  uart_gpio;
	USART_InitTypeDef debug_uart;
	/*
     config for usart2
	*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
  /* Connect PXx to USARTx_Tx */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);

	/* Connect PXx to USARTx_Rx */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

	/* Configure USART Tx as alternate function push-pull */
	uart_gpio.GPIO_Pin = GPIO_Pin_2;
	uart_gpio.GPIO_Mode = GPIO_Mode_AF;
	uart_gpio.GPIO_Speed = GPIO_Speed_40MHz;
	uart_gpio.GPIO_OType = GPIO_OType_PP;
	uart_gpio.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &uart_gpio);
	/* Configure USART Rx as alternate function push-pull */
	uart_gpio.GPIO_Pin = GPIO_Pin_3;
	GPIO_Init(GPIOA, &uart_gpio);
    
	debug_uart.USART_BaudRate = 115200;
	debug_uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	debug_uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	debug_uart.USART_Parity = USART_Parity_No;
	debug_uart.USART_StopBits = USART_StopBits_1;
	debug_uart.USART_WordLength = USART_WordLength_8b;

	/* USART configuration */
    USART_Init(USART2, &debug_uart);
	
	USART_Cmd(USART2,ENABLE);
	USART_ClearFlag(USART2, USART_FLAG_TC);
    USART_ClearITPendingBit(USART2,USART_IT_RXNE);
	USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);
}

Call example:

int main(void){ 
 CBsp bsp;
 bsp.Init();
 bsp.delay_ms(1000);
 while (1);
 return 0; 
}

reference

  1. Design of stm32 embedded system based on cortex-m3
  2. CBsp class code: http://download.csdn.net/detail/winsbb/9869686

Topics: Single-Chip Microcomputer