论坛» 活动中心» 板卡试用

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

高工
2019-01-01 18:48 1楼

在一开始的尝试后,我开始了正式的编程,首先从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

{

user_pwm_setvalue(num);

HAL_Delay(12);

}

for(num=0;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

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

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

下载不了附件

高工
2019-01-02 10:39 3楼

谢谢楼主分享

院士
2019-01-02 19:32 4楼

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

高工
2019-01-03 10:10 5楼

照猫画虎,越画越好

共5条 1/1 1 跳转至

回复

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