🥬Arduino和MPLAB X 开发STM32F103和PIC16F15376
Arduino | MPLAB X | STM32 | PIC16 | Blue Pill | Curiosity Nano | FreeRTOS | ESP32 | ESP-IDF | C/C++ | 莫尔斯电码 | 光敏电阻 | 气体检测器 | 温度记录仪 | 太阳能(电压)测量 | 体温测量
要点:
使用Arduino开发STM32F103(Blue Pill),MPLAB X 开发PIC16F15376(Curiosity Nano)
C/C++嵌入式开发
ESP32(Arduino、ESP-IDF)和STM32实时操作系统FreeRTOS
STM32使用FreeRTOS示例
在使用 FreeRTOS 时,您应该记住一些术语差异。 FreeRTOS 中的“任务”是一个程序的一部分,可以与同一程序中的其他部分同时运行。 如果您做过其他并发编程,它类似于“线程”。 但是,请注意,CMSIS-RTOS(我们的 RTOS 的抽象层)将这些并发部分称为“线程”。 因此,您可能会看到它们在整个程序中互换使用,即使它们的含义并不完全相同。
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart2;
osThreadId_t blink01Handle;
osThreadId_t blink02Handle;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
void StartBlink01(void *argument);
void StartBlink02(void *argument);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
osKernelInitialize();
const osThreadAttr_t blink01_attributes = {
.name = "blink01",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128
};
blink01Handle = osThreadNew(StartBlink01, NULL, &blink01_attributes);
/* definition and creation of blink02 */
const osThreadAttr_t blink02_attributes = {
.name = "blink02",
.priority = (osPriority_t) osPriorityBelowNormal,
.stack_size = 128
};
blink02Handle = osThreadNew(StartBlink02, NULL, &blink02_attributes);
osKernelStart();
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** 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 = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
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_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USART2_UART_Init(void)
{
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;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
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 END Header_StartBlink01 */
void StartBlink01(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
osDelay(500);
}
// In case we accidentally exit from task loop
osThreadTerminate(NULL);
/* USER CODE END 5 */
}
/* USER CODE END Header_StartBlink02 */
void StartBlink02(void *argument)
{
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
osDelay(600);
}
// In case we accidentally exit from task loop
osThreadTerminate(NULL);
/* USER CODE END StartBlink02 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
void Error_Handler(void)
{
}
#ifdef USE_FULL_ASSERT
void assert_failed(char *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
在 main() 的开头,您应该看到由 CubeMX 设置的为我们定义的线程。 请注意,我们将入口函数名称传递给 osThreadNew() 函数,一旦我们调用 osKernelStart(),该函数就会调用这些函数。 一旦 osKernelStart() 被调用,我们不希望在 main() 中的后面有任何代码,因为理想情况下,程序应该永远不会从 osKernelStart() 返回。
此时,我们的线程应该同时运行,具有自己的设置代码和永远的 while 循环。还有一个正在运行的后台调度程序任务,它负责在线程之间切换上下文。
StartBlink01() 和 StartBlink02() 是我们的线程。 每个都有自己的永远循环,并且它们应该同时运行。 虽然它们在我们的单核处理器中无法占用相同的空间和时间,但调度程序会切换它们,让我们看起来像是同时运行 2 个线程。
请注意,我们需要使用 osDelay(),而不是 HAL_Delay()。 高优先级任务中的 HAL_Delay() 可能会占用处理器,从而阻止上下文切换。 它还可以防止调度程序空闲,从而节省电量。 因此,我们使用 osDelay() 告诉调度程序在等待期间可以切换到不同的任务。
我们对blink01 和blink02 使用不同的延迟时间,以便这两个任务争夺LED 的切换。
开发环境
本文中描述的两个微控制器板(Blue Pill 和 Curiosity Nano)可以使用不同的 IDE 进行编程。 IDE是一种编程和调试软件工具,包括代码编辑器、编译环境、调试选项等。 许多 IDE 还用于通过 USB 端口连接将编译后的程序上传到微控制器板。
Arduino IDE:这个免费的 IDE 最初是为了对 Arduino 微控制器板进行编程而创建的,但如果您为其安装了库,您也可以使用它来对 Blue Pill 微控制器板进行编程。
MPLAB X IDE:由 Curiosity Nano 制造商 Microchip 制造。 这是对 Curiosity Nano 进行编程所需的免费 IDE。
Arduino和MPLAB X案例
按钮开关LED
用光敏电阻测量光量
温湿度测量
使用 LED 显示的莫尔斯电码 SOS 视觉警报
创建拍手开关
气体检测器
互联网温度记录仪
物联网花盆湿度传感器
物联网太阳能(电压)测量
数字体温测量(温度计)
社交距离警报
20 秒洗手计时器
ESP32和STM32实时操作系统FreeRTOS
ESP32(Arduino)多任务FreeRTOS
队列管理
更改任务的优先级
如何使用FreeRTOS结构队列接收多个任务的数据
如何使用 vTaskDelete() API 删除任务
使用队列集
创建带队列的邮箱
创建一次性和自动重新加载定时器
二进制信号量 – 使用 Arduino 进行任务中断同步的示例
使用 Arduino 计数信号量示例
斥教程 – 避免优先级反转
递归互斥以避免死锁
使用 Arduino 的 FreeRTOS 中断管理示例
ESP-IDF示例FreeRTOS
STM32开发调试FreeRTOS
Last updated