这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 跳动的心之二——照猫画虎编程序

共5条 1/1 1 跳转至

跳动的心之二——照猫画虎编程序

高工
2019-01-01 18:48:51     打赏

在一开始的尝试后,我开始了正式的编程,首先从STM32CubeMX开始,一点开,emmm,跟教程里原来的界面有些不一样了。

1537253110317089.png

以前的界面。

image.png

现在的界面。这一升级,又得重新熟悉界面了。

升级后界面不太一样,那我就用新版的来讲解一下吧。

image.png

首先还是先选板子。

image.png

选择默认模式初始化所有外设

image.png

选择项目管理进行配置。

image.png

image.png

外设配置。配置ADC1。

image.png

配置TIM5。

image.png

配置TIM9。

image.png

最后,点击这里生成工程代码。

image.png

打开工程后,我把所有代码全加了进去。

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "stm32f4xx_hal.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

// these variables are volatile because they are used during the interrupt service routine!


#define true 1

#define false 0

int BPM;                   // used to hold the pulse rate

int Signal;                // holds the incoming raw data

int IBI = 600;             // holds the time between beats, must be seeded!

unsigned char Pulse = false;     // true when pulse wave is high, false when it's low

unsigned char QS = false;        // becomes true when Arduoino finds a beat.

int rate[10];                    // array to hold last ten IBI values

unsigned long sampleCounter = 0;          // used to determine pulse timing

unsigned long lastBeatTime = 0;           // used to find IBI

int P =512;                      // used to find peak in pulse wave, seeded

int T = 512;                     // used to find trough in pulse wave, seeded

int thresh = 512;                // used to find instant moment of heart beat, seeded

int amp = 100;                   // used to hold amplitude of pulse waveform, seeded

int Num;

int num;

unsigned char firstBeat = true;     // used to seed rate array so we startup with reasonableBPM

unsigned char secondBeat = false;  // used to seed rate array so we startup with reasonableBPM

/* USER CODE END Includes */


/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */


/* USER CODE END PTD */


/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */


/* USER CODE END PD */


/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */


/* USER CODE END PM */


/* Private variables ---------------------------------------------------------*/

ADC_HandleTypeDef hadc1;


TIM_HandleTypeDef htim5;

TIM_HandleTypeDef htim9;


UART_HandleTypeDef huart2;


/* USER CODE BEGIN PV */


/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_USART2_UART_Init(void);

static void MX_ADC1_Init(void);

static void MX_TIM5_Init(void);

static void MX_TIM9_Init(void);

/* USER CODE BEGIN PFP */


/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

void user_pwm_setvalue(uint16_t value)

{

  TIM_OC_InitTypeDef sConfigOC;

  sConfigOC.OCMode = TIM_OCMODE_PWM1;

  sConfigOC.Pulse = value;

  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

  HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1);

  HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_1);  

 }

/* USER CODE END 0 */


/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */


  /* 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_USART2_UART_Init();

  MX_ADC1_Init();

  MX_TIM5_Init();

  MX_TIM9_Init();

  /* USER CODE BEGIN 2 */


  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

for(num=0;num<BPM;num++)

{

user_pwm_setvalue(num);

HAL_Delay(12);

}

for(num=0;num<BPM;num++)

{

user_pwm_setvalue(BPM-num);

HAL_Delay(20);

}

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


/**

  * @brief System Clock Configuration

  * @retval None

  */

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  /**Configure the main internal regulator output voltage 

  */

  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /**Initializes the CPU, AHB and APB busses clocks 

  */

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

  RCC_OscInitStruct.HSIState = RCC_HSI_ON;

  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;

  RCC_OscInitStruct.PLL.PLLM = 16;

  RCC_OscInitStruct.PLL.PLLN = 336;

  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;

  RCC_OscInitStruct.PLL.PLLQ = 4;

  RCC_OscInitStruct.PLL.PLLR = 2;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  {

    Error_Handler();

  }

  /**Initializes the CPU, AHB and APB busses clocks 

  */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

  {

    Error_Handler();

  }

}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

unsigned int runningTotal;

if(htim->Instance==htim9.Instance)

{

Signal=HAL_ADC_GetValue(&hadc1); // read the Pulse Senso

sampleCounter += 2;                         // keep track of the time in mS with this variable

Num = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

HAL_ADC_Start(&hadc1); //restart ADC conversion

//  find the peak and trough of the pulse wave

  if(Signal < thresh && Num > (IBI/5)*3){       // avoid dichrotic noise by waiting 3/5 of last IBI

    if (Signal < T){                        // T is the trough

      T = Signal;                         // keep track of lowest point in pulse wave

    }

  }

  if(Signal > thresh && Signal > P){          // thresh condition helps avoid noise

    P = Signal;                             // P is the peak

  }                                        // keep track of highest point in pulse wave

  //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT

  // signal surges up in value every time there is a pulse

  if (Num > 250){                                   // avoid high frequency noise

    if ( (Signal > thresh) && (Pulse == false) && (Num > (IBI/5)*3) ){        

      Pulse = true;                               // set the Pulse flag when we think there is a pulse

      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);                // turn on pin 13 LED

      IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS

      lastBeatTime = sampleCounter;               // keep track of time for next pulse

      if(secondBeat){                        // if this is the second beat, if secondBeat == TRUE

        secondBeat = false;                  // clear secondBeat flag

        for(int i=0; i<=9; i++){             // seed the running total to get a realisitic BPM at startup

          rate[i] = IBI;                      

        }

      }

      if(firstBeat){                         // if it's the first time we found a beat, if firstBeat == TRUE

        firstBeat = false;                   // clear firstBeat flag

        secondBeat = true;                   // set the second beat flag

 //       sei();                               // enable interrupts again

        return;                              // IBI value is unreliable so discard it

      }   

      // keep a running total of the last 10 IBI values

      runningTotal = 0;                  // clear the runningTotal variable    

      for(int i=0; i<=8; i++){                // shift data in the rate array

        rate[i] = rate[i+1];                  // and drop the oldest IBI value

        runningTotal += rate[i];              // add up the 9 oldest IBI values

      }

      rate[9] = IBI;                          // add the latest IBI to the rate array

      runningTotal += rate[9];                // add the latest IBI to runningTotal

      runningTotal /= 10;                     // average the last 10 IBI values

      BPM = 60000/runningTotal;       // how many beats can fit into a minute? that's BPM!

      QS = true;                              // set Quantified Self flag

      // QS FLAG IS NOT CLEARED INSIDE THIS ISR

    }                       

  }

  if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over

    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);        // turn off pin 13 LED

    Pulse = false;                         // reset the Pulse flag so we can do it again

    amp = P - T;                           // get amplitude of the pulse wave

    thresh = amp/2 + T;                    // set thresh at 50% of the amplitude

    P = thresh;                            // reset these for next time

    T = thresh;

  }

  if (Num > 2500){                           // if 2.5 seconds go by without a beat

    thresh = 512;                          // set thresh default

    P = 512;                               // set P default

    T = 512;                               // set T default

    lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        

    firstBeat = true;                      // set these to avoid noise

    secondBeat = false;                    // when we get the heartbeat back

  }

}

}

/**

  * @brief ADC1 Initialization Function

  * @param None

  * @retval None

  */

static void MX_ADC1_Init(void)

{


  /* USER CODE BEGIN ADC1_Init 0 */


  /* USER CODE END ADC1_Init 0 */


  ADC_ChannelConfTypeDef sConfig = {0};


  /* USER CODE BEGIN ADC1_Init 1 */


  /* USER CODE END ADC1_Init 1 */

  /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 

  */

  hadc1.Instance = ADC1;

  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

  hadc1.Init.Resolution = ADC_RESOLUTION_12B;

  hadc1.Init.ScanConvMode = DISABLE;

  hadc1.Init.ContinuousConvMode = DISABLE;

  hadc1.Init.DiscontinuousConvMode = DISABLE;

  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

  hadc1.Init.NbrOfConversion = 1;

  hadc1.Init.DMAContinuousRequests = DISABLE;

  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

  if (HAL_ADC_Init(&hadc1) != HAL_OK)

  {

    Error_Handler();

  }

  /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 

  */

  sConfig.Channel = ADC_CHANNEL_6;

  sConfig.Rank = 1;

  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN ADC1_Init 2 */


  /* USER CODE END ADC1_Init 2 */


}


/**

  * @brief TIM5 Initialization Function

  * @param None

  * @retval None

  */

static void MX_TIM5_Init(void)

{


  /* USER CODE BEGIN TIM5_Init 0 */


  /* USER CODE END TIM5_Init 0 */


  TIM_ClockConfigTypeDef sClockSourceConfig = {0};

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  TIM_OC_InitTypeDef sConfigOC = {0};


  /* USER CODE BEGIN TIM5_Init 1 */


  /* USER CODE END TIM5_Init 1 */

  htim5.Instance = TIM5;

  htim5.Init.Prescaler = 50;

  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim5.Init.Period = 1999;

  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  if (HAL_TIM_Base_Init(&htim5) != HAL_OK)

  {

    Error_Handler();

  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

  if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK)

  {

    Error_Handler();

  }

  if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)

  {

    Error_Handler();

  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

  if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)

  {

    Error_Handler();

  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;

  sConfigOC.Pulse = 0;

  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

  if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN TIM5_Init 2 */


  /* USER CODE END TIM5_Init 2 */

  HAL_TIM_MspPostInit(&htim5);


}


/**

  * @brief TIM9 Initialization Function

  * @param None

  * @retval None

  */

static void MX_TIM9_Init(void)

{


  /* USER CODE BEGIN TIM9_Init 0 */


  /* USER CODE END TIM9_Init 0 */


  TIM_ClockConfigTypeDef sClockSourceConfig = {0};


  /* USER CODE BEGIN TIM9_Init 1 */


  /* USER CODE END TIM9_Init 1 */

  htim9.Instance = TIM9;

  htim9.Init.Prescaler = 100;

  htim9.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim9.Init.Period = 0;

  htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  if (HAL_TIM_Base_Init(&htim9) != HAL_OK)

  {

    Error_Handler();

  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

  if (HAL_TIM_ConfigClockSource(&htim9, &sClockSourceConfig) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN TIM9_Init 2 */


  /* USER CODE END TIM9_Init 2 */


}


/**

  * @brief USART2 Initialization Function

  * @param None

  * @retval None

  */

static void MX_USART2_UART_Init(void)

{


  /* USER CODE BEGIN USART2_Init 0 */


  /* USER CODE END USART2_Init 0 */


  /* USER CODE BEGIN USART2_Init 1 */


  /* USER CODE END USART2_Init 1 */

  huart2.Instance = USART2;

  huart2.Init.BaudRate = 115200;

  huart2.Init.WordLength = UART_WORDLENGTH_8B;

  huart2.Init.StopBits = UART_STOPBITS_1;

  huart2.Init.Parity = UART_PARITY_NONE;

  huart2.Init.Mode = UART_MODE_TX_RX;

  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart2.Init.OverSampling = UART_OVERSAMPLING_16;

  if (HAL_UART_Init(&huart2) != HAL_OK)

  {

    Error_Handler();

  }

  /* USER CODE BEGIN USART2_Init 2 */


  /* USER CODE END USART2_Init 2 */


}


/**

  * @brief GPIO Initialization Function

  * @param None

  * @retval None

  */

static void MX_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};


  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOC_CLK_ENABLE();

  __HAL_RCC_GPIOH_CLK_ENABLE();

  __HAL_RCC_GPIOA_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);


  /*Configure GPIO pin : B1_Pin */

  GPIO_InitStruct.Pin = B1_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);


  /*Configure GPIO pin : LD2_Pin */

  GPIO_InitStruct.Pin = LD2_Pin;

  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);


}


/* USER CODE BEGIN 4 */


/* USER CODE END 4 */


/**

  * @brief  This function is executed in case of error occurrence.

  * @retval None

  */

void Error_Handler(void)

{

  /* USER CODE BEGIN Error_Handler_Debug */

  /* User can add his own implementation to report the HAL error return state */


  /* USER CODE END Error_Handler_Debug */

}


#ifdef  USE_FULL_ASSERT

/**

  * @brief  Reports the name of the source file and the source line number

  *         where the assert_param error has occurred.

  * @param  file: pointer to the source file name

  * @param  line: assert_param error line source number

  * @retval None

  */

void assert_failed(uint8_t *file, uint32_t line)

  /* USER CODE BEGIN 6 */

  /* User can add his own implementation to report the file name and line number,

     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

按照引脚图连接好,一切准备就绪后通电,但始终不会亮,就像这样。

3264.jpg

我一度怀疑自己是不是接错线了,反复查看确认,LED小灯和pulse sensor都是电源接5V(3.3V也接过),地接地,LED小灯驱动引脚接PA0,pulse sensor驱动接PA6,但还是无法正常运行。

反复查看程序和接线,就是没找出问题。不过,有一个疑问,就是教程中的主函数中的num,前面没定义,好吧,我在一开始加上定义后,还是没法运行。看来,得另想办法了。。

image.png

我把程序献上,有哪个高手能帮我找出问题所在的,小弟感激不尽!!

heartly.zip




关键词: 跳动的心     pulse sensor     程序    

专家
2019-01-02 08:47:08     打赏
2楼

该信息正在审核中,请耐心等待,很快哦!

下载不了附件


管理员
2019-01-02 10:39:55     打赏
3楼

谢谢楼主分享


院士
2019-01-02 19:32:48     打赏
4楼

我也觉得这个最新版本的cubeMX长得太难看了。


高工
2019-01-03 10:10:52     打赏
5楼

照猫画虎,越画越好


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]