光立方

  • 硬件

STM32F103C8T6

4个SG90舵机

4路继电器

一个超声波

  • MX配置
  • 程序编写
AllHead.h
cpp
#ifndef __ALLHEAD_H
#define __ALLHEAD_H
#include "main.h"
#include "dma.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

#include "CallBack.h"
#include "Public.h"
#include "System.h"
#include "System_Init.h"


# include <string.h>
# include <stdarg.h>
# include <stdlib.h>
# include "stdio.h"
#include "stdint.h"
#include "math.h"

#include "Steer.h"
#include "ultrasound.h"
#include "Pwm_Led.h"
#include "IW_Dog.h"
#include "Relay.h"
#include "Voice.h"
#include "BlueTooth.h"

#include "Task.h"

#endif
Task.c
cpp
/***************************************************************************
 * File: Task.c
 * Author: Luckys.
 * Date: 2023/06/23
 * description: 
****************************************************************************/
#include "AllHead.h"

/*====================================static function declaration area BEGIN====================================*/
static void TasksHandle_30MS(void);
static void TasksHandle_50MS(void);
static void TasksHandle_100MS(void);
static void TasksHandle_150MS(void);
static void TasksHandle_1S(void);
static void TasksHandle_1500MS(void);
/*====================================static function declaration area   END====================================*/

Task_t Task[] =
{
	{FALSE, 30, 30, TasksHandle_30MS},    // task Period: 10ms
	{FALSE, 50, 50, TasksHandle_50MS},    // task Period: 50ms
	{FALSE, 100, 100, TasksHandle_100MS},    // task Period: 100ms
	{FALSE, 150, 150, TasksHandle_150MS},    // task Period: 150ms
	{FALSE, 1000, 1000, TasksHandle_1S},    // task Period: 1s
	{FALSE, 1500, 1500, TasksHandle_1500MS},    // task Period: 1.5s
};

/*====================================variable definition declaration area BEGIN===================================*/

// 
uint8_t ucTasks_Max = sizeof(Task) / sizeof(Task[0]);

/*====================================variable definition declaration area   END===================================*/

static void TasksHandle_30MS(void)
{
	// 【呼吸灯1】
	if (TRUE == Voice.Pwm_Led_Flag_Buf[LED1])
	{
		Pwm_Led.Pwm_Led_Breathing(LED1);
	}
	else
	{
		Pwm_Led.Pwm_Led_Duty_Control(LED1, 101);	// 常亮
	}
	
	// 【呼吸灯2】
	if (TRUE == Voice.Pwm_Led_Flag_Buf[LED2])
	{
		Pwm_Led.Pwm_Led_Breathing(LED2);
	}
	else
	{
		Pwm_Led.Pwm_Led_Duty_Control(LED2, 101);	// 常亮
	}

	// 【呼吸灯3】
	if (TRUE == Voice.Pwm_Led_Flag_Buf[LED3])
	{
		Pwm_Led.Pwm_Led_Breathing(LED3);
	}
	else
	{
		Pwm_Led.Pwm_Led_Duty_Control(LED3, 101);	// 常亮
	}	

	// 【呼吸灯4】
	if (TRUE == Voice.Pwm_Led_Flag_Buf[LED4])
	{
		Pwm_Led.Pwm_Led_Breathing(LED4);
	}
	else
	{
		Pwm_Led.Pwm_Led_Duty_Control(LED4, 101);	// 常亮
	}
}

static void TasksHandle_50MS(void)
{
	HAL_GPIO_TogglePin(SYS_LED_GPIO_Port, SYS_LED_Pin);	// 系统灯运行
}

static void TasksHandle_100MS(void)
{
	ultrasound.ultrasound_Get_Value();	// 超声波读取值
}

static void TasksHandle_150MS(void)
{
	if (TRUE == Voice.Steer_Auto_Flag)	// 启动鲜花全自动
	{	
		ultrasound.ultrasound_Handler();	// 超声波处理函数
	}
}

static void TasksHandle_1S(void)
{
	if (TRUE == Voice.Steer_Auto_Flag)	// 启动鲜花全自动
	{
		Steer.Steer_Handler();	// 舵机处理函数
	}
	else
	{
		__Steer_Reset();	// 舵机复位
	}
}

static void TasksHandle_1500MS(void)
{
	IW_Dog.IW_Dog_Feed();	// 喂狗
}
System_Init.c
cpp
/***************************************************************************
 * File: System_Init.c
 * Author: Luckys.
 * Date: 2023/06/23
 * description: 存放系统初始化
****************************************************************************/
#include "AllHead.h"

/*====================================static function declaration area BEGIN====================================*/

static void Hardware_Init(void);

/*====================================static function declaration area   END====================================*/


System_Init_t System_Init = 
{
    Hardware_Init
};

/*
* @function: Hardware_Init
* @param: None
* @retval: None
* @brief: 硬件初始化
*/
static void Hardware_Init(void)
{
    IW_Dog.IW_Dog_Init();   // 看门狗初始化
    Relay.Relay_Init(); // 继电器初始化
    Steer.Steer_Init(); // 舵机初始化
    Pwm_Led.Pwm_Led_Init(); // PWM灯带初始化
    Voice.Voice_Init(); // ASR初始化
	BlueTooth.BlueTooth_Init();	// 蓝牙初始化
	HAL_TIM_Base_Start_IT(&htim3);  // 任务调度定时器
    BlueTooth.BlueTooth_Send_Data((uint8_t*)"Init OK\r\n", strlen("Init OK\r\n"));
}
System.c
cpp
/***************************************************************************
 * File: System.c
 * Author: Luckys.
 * Date: 2023/06/23
 * description: 
****************************************************************************/
#include "AllHead.h"


/*====================================static function declaration area BEGIN====================================*/

static void Run(void);
static void SysTem_Func_Fail_Handler(void); 
static void System_Assert_Fail_Handler(void);   
static void Task_Marks_Handler(void);
static void Task_Pro_Handler(void);

/*====================================static function declaration area   END====================================*/

System_t System = 
{
    Run,
    SysTem_Func_Fail_Handler,
    System_Assert_Fail_Handler,
    Task_Marks_Handler
};

/*
* @function: Run
* @param: None
* @retval: None
* @brief: 
*/
static void Run(void)
{
    Task_Pro_Handler(); // 
}

/*
* @function: SysTem_Func_Fail_Handler
* @param: None
* @retval: None
* @brief: 
*/
static void SysTem_Func_Fail_Handler(void)
{
    
}

/*
* @function: System_Assert_Fail_Handler
* @param: None
* @retval: None
* @brief: 
*/
static void System_Assert_Fail_Handler(void)
{
    
}

/*
* @function: Task_Marks_Handler
* @param: None
* @retval: None
* @brief: 
*/
static void Task_Marks_Handler(void)
{
    uint8_t i;

    for (i = 0; i < ucTasks_Max; i++)
    {
        if (Task[i].Task_Cnt)   // 
        {
            Task[i].Task_Cnt--; // 
            if (0 == Task[i].Task_Cnt)  // 
            {
                Task[i].Task_Cnt = Task[i].Task_Timer;  // 
                Task[i].Run_Status = TRUE;  // 
            }
        }
    }
}

/*
* @function: Task_Pro_Handler
* @param: None
* @retval: None
* @brief: 
*/
static void Task_Pro_Handler(void)
{
    uint8_t i;

    for (i = 0; i < ucTasks_Max; i++)
    {
        if (Task[i].Run_Status) // 
        {
            Task[i].Run_Status = FALSE;
            Task[i].Task_Hook();    // 
        }
    }
}
Public.c
cpp
/***************************************************************************
 * File: Public.c
 * Author: Luckys.
 * Date: 2023/06/23
 * description: 存放通用
 -----------------------------------
 上位机通信选择USART3
                    PB10(TX)
                    PB11(RX)
 -----------------------------------
****************************************************************************/
#include "AllHead.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
/*====================================static function declaration area BEGIN====================================*/

static void Memory_Clear(uint8_t*, uint16_t);   
static void Public_Delay_ms(uint16_t);  
static void Public_Delay_us(uint16_t);
static void Memory_Copy(char*, const char*, uint16_t);

/*====================================static function declaration area   END====================================*/

Public_t Public = 
{
    Memory_Clear,
    Public_Delay_ms,
    Public_Delay_us,
    Memory_Copy
};


/*
* @function: Memory_Clear
* @param: pucBuffer -> 内存首地址 LEN -> 内存长度
* @retval: None
* @brief: 描述
*/
static inline void Memory_Clear(uint8_t* pucBuffer, uint16_t LEN)
{
    uint16_t i;

    for (i = 0; i < LEN; i++)
    {
        *(pucBuffer + i) = (uint8_t)0;
    }
}

/*
* @function: Public_Delay_ms
* @param: ms -> 需要延时的时间(ms)
* @retval: None
* @brief: 系统ms延时
*/
static void Public_Delay_ms(uint16_t ms)
{
    HAL_Delay(ms);
}

/*
* @function: Public_Delay_us
* @param: us -> 需要延时的时间(us)
* @retval: None
* @brief: 系统us延时
*/
static void Public_Delay_us(uint16_t us)
{
    uint8_t i;
    // 通过示波器测量进行校准
    while(us--)
    {
        for (i = 0; i < 7; i++);
    }
}

/*
* @function: Memory_Copy
* @param: dest -> 要复制到的指针地址 src -> 被复制的指针地址 count -> 大小(数组用sizeof 字符串用strlen)
* @retval: None
* @brief: 复制固定长度数组/字符串
*/
static inline void Memory_Copy(char* dest, const char* src, uint16_t count)
{
    uint16_t i;

    for (i = 0; i < count; i++) 
    {
        dest[i] = src[i];
    }    
}

#if 0
// 重定向
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 0x0A);

    return ch;
}
#endif

CallBack.c
cpp
/***************************************************************************
 * File: CallBack.c
 * Author: Luckys.
 * Date: 2023/06/19
 * description: 存放中断函数
****************************************************************************/
#include "AllHead.h"

/*
* @function: HAL_TIM_PeriodElapsedCallback
* @param: htim -> 处理定时器的结构体指针
* @retval: None
* @brief: 定时器回调函数
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == htim3.Instance)
    {
        System.Task_Marks_Handler();    // 任务标记
    } 
}

/*
* @function: xxx
* @param: None
* @retval: None
* @brief: 输入捕获回调函数
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2)
    {
        switch(ultrasound.Run_Status)
        {
            case 1:
            {
                ultrasound.Timer_Cnt_Buf[0] = TIM2->CCR1;   // 获取计数值
                __HAL_TIM_SET_CAPTUREPOLARITY(Ultrasound_Timer, Ultrasound_Channel, TIM_INPUTCHANNELPOLARITY_FALLING);   // 下降沿触发
                ultrasound.Run_Status++;
                break;
            }
            case 2:
            {
                ultrasound.Timer_Cnt_Buf[1] = TIM2->CCR1;   // 获取计数值
                HAL_TIM_IC_Stop_IT(Ultrasound_Timer, Ultrasound_Channel);   // 停止捕获
                ultrasound.Run_Status++;
                break;
            }
        }
    }
}

/*
* @function: USART2_IRQHandler
* @param: None
* @retval: None
* @brief: 串口2中断服务函数(语音)
*/
void USART2_IRQHandler(void)
{
    if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != 0x00)
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart2); // 清除标志位
        Voice.Voice_Protocol(); // 协议解析
    }
    HAL_UART_IRQHandler(&huart2);
}

void USART3_IRQHandler(void)
{
    if (__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE) != 0x00u)   // 判断是否发生空闲中断
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart3); // 清除空闲中断标志位
        HAL_UART_DMAStop(&huart3);          // 停止DMA接收
        BlueTooth.BlueTooth_Analyze();  // 数据解析
    }    
    HAL_UART_IRQHandler(&huart3);
}
BlueTooth.h
cpp
#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H

// 接收缓存最大值
#define BlueTooth_REC_MAX_LEN 66
// 使用串口
#define BLUE_TOOTH_USE_UART huart3


typedef struct
{
    uint8_t *BlueTooth_Rec_Buffer;          // 串口3接收缓存数组指针
    void (*BlueTooth_Init)(void);       // 串口3初始化   
    void (*BlueTooth_Send_Data)(uint8_t *, uint16_t);   // 串口3发送数据函数
    void (*BlueTooth_Analyze)(void);
} BlueTooth_st;

extern BlueTooth_st BlueTooth;


#endif
BlueTooth.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
蓝牙接线:
        PB10(TX) --- 蓝牙RX
        PB11(RX) --- 蓝牙TX
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private variables=========================================================*/
uint8_t BlueTooth_Rec_Arr[BlueTooth_REC_MAX_LEN] = {0};   // 定义一个接收数组

/* Private function prototypes===============================================*/
static void BlueTooth_Init(void);
static void BlueTooth_Analyze(void);
static void BlueTooth_Send_Data(uint8_t *str, uint16_t len);
/* Public variables==========================================================*/
BlueTooth_st BlueTooth = 
{
    .BlueTooth_Rec_Buffer = BlueTooth_Rec_Arr,  
    .BlueTooth_Init = &BlueTooth_Init,
    .BlueTooth_Send_Data = &BlueTooth_Send_Data,
    .BlueTooth_Analyze = &BlueTooth_Analyze
};

/*
* @function: BlueTooth_Init
* @param: None
* @retval: None
* @brief: 串口3初始化
*/
static void BlueTooth_Init(void)
{
    __HAL_UART_ENABLE_IT(&BLUE_TOOTH_USE_UART, UART_IT_IDLE);    // 使能串口3空闲中断
    HAL_UART_Receive_DMA(&BLUE_TOOTH_USE_UART, BlueTooth.BlueTooth_Rec_Buffer, BlueTooth_REC_MAX_LEN);  // 使能串口3DMA接收
}

/*
* @function: BlueTooth_Send_Data
* @param: None
* @retval: None
* @brief: 串口3发送数据函数
*/
static void BlueTooth_Send_Data(uint8_t *str, uint16_t len)
{
    HAL_UART_Transmit(&BLUE_TOOTH_USE_UART, str, len, 0x0A);
}

/*
* @function: BlueTooth_Analyze
* @param: None
* @retval: None
* @brief: 数据解析
*/
static void BlueTooth_Analyze(void)
{
    if (strncmp((char *)BlueTooth.BlueTooth_Rec_Buffer, "Ctrl_LED1", strlen("Ctrl_LED1")) == 0)
    {
        static uint8_t flag1 = RELAY_OFF;
        flag1 = !flag1;
        Relay.Relay_Control(RELAY_A, flag1);
    }
    else if (strncmp((char *)BlueTooth.BlueTooth_Rec_Buffer, "Ctrl_LED2", strlen("Ctrl_LED2")) == 0)
    {
        static uint8_t flag2 = RELAY_OFF;
        flag2 = !flag2;
        Relay.Relay_Control(RELAY_B, flag2);
    }
    else if (strncmp((char *)BlueTooth.BlueTooth_Rec_Buffer, "Ctrl_LED3", strlen("Ctrl_LED3")) == 0)
    {
        static uint8_t flag3 = RELAY_OFF;
        flag3 = !flag3;        
        Relay.Relay_Control(RELAY_C, flag3);
    }
    else if (strncmp((char *)BlueTooth.BlueTooth_Rec_Buffer, "Ctrl_LED4", strlen("Ctrl_LED4")) == 0)
    {
        static uint8_t flag4 = RELAY_OFF;
        flag4 = !flag4;        
        Relay.Relay_Control(RELAY_D, flag4);
    }        

    memset(BlueTooth.BlueTooth_Rec_Buffer, 0, strlen((char*)BlueTooth.BlueTooth_Rec_Buffer));  // 数组清0
    HAL_UART_Receive_DMA(&BLUE_TOOTH_USE_UART, BlueTooth.BlueTooth_Rec_Buffer, BlueTooth_REC_MAX_LEN);  // 使能串口3DMA接收
}
Voice.h
cpp
#ifndef __VOICE_H
#define __VOICE_H

// ASR串口
#define huart_ASR	huart2

// 串口接收最大长度
#define Voice_Rec_Buffer_LENGTH	(uint8_t)20
// 协议长度是4个字节
#define Protocol_Data_LEN	(uint8_t)4

// 定义结构体类型
typedef struct
{
    uint8_t Steer_Auto_Flag;    // 鲜花复位/全自动标志位
    uint8_t Steer_Switch_Closure_Flag; // 启动/取消自动闭合
    uint8_t Pwm_Led_Flag_Buf[4];    // 打开/关闭呼吸灯标志位数组
    uint8_t ucVoice_EndData[4]; // 语音接收有效协议数组
	uint8_t* pucRec_Buffer;	// 接收缓存
	void (*Voice_Init)(void);	// ASR初始化
	void (*Voice_SendString)(uint8_t*);	// 发送字符串给ASR
	void (*Voice_Protocol)(void);	// 接口协议
} Voice_st;

extern Voice_st Voice;
#endif
Voice.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
语音模块通信:使用USART2
            PA2(TX) ---> 模块RX(PA6)
            PA3(RX) ---> 模块TX(PA5)
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private variables=========================================================*/
static uint8_t ucVoice_Rec_Buffer[Voice_Rec_Buffer_LENGTH] = {0x00};
/* Private function prototypes===============================================*/
static void Voice_Init(void);
static void Voice_SendString(uint8_t *str);
static void Voice_Protocol(void);
/* Public variables==========================================================*/
Voice_st Voice = 
{
    .Steer_Auto_Flag = FALSE,
    .Steer_Switch_Closure_Flag = FALSE,
    .Pwm_Led_Flag_Buf = {FALSE, FALSE, FALSE, FALSE},
    .ucVoice_EndData = {0xFF, 0xFF, 0xFF, 0xFF},
    .pucRec_Buffer = ucVoice_Rec_Buffer,
    .Voice_Init = &Voice_Init,
    .Voice_SendString = &Voice_SendString,
    .Voice_Protocol = &Voice_Protocol
};

/*
* @function: Voice_Init
* @param: None
* @retval: None
* @brief: 语音初始化
*/
static void Voice_Init(void)
{
    __HAL_UART_ENABLE_IT(&huart_ASR, UART_IT_IDLE); // 使能串口空闲中断
    HAL_UART_Receive_DMA(&huart_ASR, Voice.pucRec_Buffer, (uint16_t)Voice_Rec_Buffer_LENGTH);   // 使能DMA接收
}

/*
* @function: Voice_SendString
* @param: None
* @retval: None
* @brief: ASR发送字符串
*/
static void Voice_SendString(uint8_t *str)
{
    HAL_UART_Transmit(&huart_ASR,str,strlen((const char*)str),100);
}

/*
* @function: Voice_Protocol
* @param: None
* @retval: None
* @brief: 语音协议解析
*/
static void Voice_Protocol(void)
{
    uint8_t Temp_Array[4] = {0x00};
    uint8_t i = 0, Index = 0;

    HAL_UART_DMAStop(&huart_ASR);   // 串口停止DMA接收

    for (i = 0; i < Voice_Rec_Buffer_LENGTH; i++) // 
    {
        if (0 == Index) // 检测键值起始数据0xAA
        {
            if (*(Voice.pucRec_Buffer + i) != 0xAA)
            {
                continue;
            }
        }
        Temp_Array[Index] = *(Voice.pucRec_Buffer + i);

        if (Protocol_Data_LEN == Index) // 已读取4字节
        {
            break;
        }
        Index++;
    }
    HAL_UART_Receive_DMA(&huart_ASR, Voice.pucRec_Buffer, (uint16_t)Voice_Rec_Buffer_LENGTH);   // 使能DMA接收

    // 处理数据
    if (Protocol_Data_LEN == Index)
    {
        if ((0xAA == Temp_Array[0]) && (0xBB == Temp_Array[3])) // 判断帧头、帧尾
        {
            switch (Temp_Array[1])  // 判断主指令
            {
                case 0x01:  // 【打开/关闭灯带1】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Relay.Relay_Control(RELAY_A, RELAY_ON);
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Relay.Relay_Control(RELAY_A, RELAY_OFF);
                    }
                    break;
                }
                case 0x02:  // 【打开/关闭灯带2】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_B, RELAY_ON);
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_B, RELAY_OFF);
                    }
                    break;
                }
                case 0x03:  // 【打开/关闭灯带3】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_C, RELAY_ON);
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_C, RELAY_OFF);
                    }
                    break;
                }
                case 0x04:  // 【打开/关闭灯带4】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_D, RELAY_ON);
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        // Relay.Relay_Control(RELAY_D, RELAY_OFF);
                    }
                    break;
                }
                case 0x05:  // 【打开/关闭呼吸灯1】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED1] = TRUE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED1] = FALSE;
                    }
                    break;
                }
                case 0x06:  // 【打开/关闭呼吸灯2】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED2] = TRUE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED2] = FALSE;
                    }
                    break;
                }   
                case 0x07:  // 【打开/关闭呼吸灯3】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED3] = TRUE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED3] = FALSE;
                    }
                    break;
                }
                case 0x08:  // 【打开/关闭呼吸灯4】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED4] = TRUE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Pwm_Led_Flag_Buf[LED4] = FALSE;
                    }
                    break;
                } 
                case 0x09:  // 【启动自动闭合/取消自动闭合】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Steer_Switch_Closure_Flag = TRUE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Steer_Switch_Closure_Flag = FALSE;
                    }                    
                    break;
                }   
                case 0x0A:  // 【鲜花复位/启动鲜花全自动】
                {
                    if (0x00 == Temp_Array[2])
                    {
                        Voice.Steer_Auto_Flag = FALSE;
                    }
                    else if (0x01 == Temp_Array[2])
                    {
                        Voice.Steer_Auto_Flag = TRUE;
                    }  
                }
                case 0x0B:
                {
                    if (0x00 == Temp_Array[2])  // 打开风扇
                    {
                        Relay.Relay_Control(RELAY_B, RELAY_ON);
                    }
                    else if (0x01 == Temp_Array[2]) // 关闭风扇
                    {
                        Relay.Relay_Control(RELAY_B, RELAY_OFF);
                    }                     
                    break;
                }
                default:break;                                         
            }
        }
        else
        {
            return;
        }
    }
}
Relay.h
cpp
#ifndef __RELAY_H
#define __RELAY_H

// 打开全部继电器
#define __Relay_All_ON() do {   \
    Relay.Relay_Control(RELAY_A, RELAY_ON); \
    Relay.Relay_Control(RELAY_B, RELAY_ON); \
    Relay.Relay_Control(RELAY_C, RELAY_ON); \
    Relay.Relay_Control(RELAY_D, RELAY_ON); \
} while(0)
// 关闭全部继电器
#define __Relay_All_OFF() do {   \
    Relay.Relay_Control(RELAY_A, RELAY_OFF); \
    Relay.Relay_Control(RELAY_B, RELAY_OFF); \
    Relay.Relay_Control(RELAY_C, RELAY_OFF); \
    Relay.Relay_Control(RELAY_D, RELAY_OFF); \
} while(0)


// 继电器开关状态枚举
typedef enum
{
    RELAY_OFF = 0x00,
    RELAY_ON = 0x01
} Relay_Switch_Status_et;

// 继电器数量
typedef enum
{
    RELAY_A = 0x00,
    RELAY_B = 0x01,
    RELAY_C = 0x02,
    RELAY_D = 0x03
} Relay_Number_et;

typedef struct
{
    uint8_t ucRelay_Status_Buf[4];  // 存储继电器当前状态
    void (*Relay_Init)(void);  // 继电器初始化
    void (*Relay_Control)(Relay_Number_et, Relay_Switch_Status_et); // 继电器控制
} Relay_st;

extern Relay_st Relay;
#endif
Relay.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
继电器接线:
        PA6 --- 继电器A
        PA7 --- 继电器B
        PB0 --- 继电器C
        PB1 --- 继电器D
        高电平触发, 3.3V驱动
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

//* Private function prototypes===============================================*/
static void Relay_Init(void);
static void Relay_Control(Relay_Number_et Relay_x, Relay_Switch_Status_et status);
/* Public variables==========================================================*/
Relay_st Relay = 
{
    .ucRelay_Status_Buf = {RELAY_OFF, RELAY_OFF, RELAY_OFF, RELAY_OFF},
    .Relay_Init = &Relay_Init,
    .Relay_Control = &Relay_Control
};

/*
* @function: Relay_Init
* @param: None
* @retval: None
* @brief: 继电器初始化
*/
static void Relay_Init(void)
{
    __Relay_All_OFF();  // 关闭全部继电器
}

/*
* @function: Relay_Control
* @param: None
* @retval: None
* @brief: 继电器控制
*/
static void Relay_Control(Relay_Number_et Relay_x, Relay_Switch_Status_et status)
{
    switch (Relay_x)
    {
        case RELAY_A:
        {
            if (RELAY_ON == status) // 打开继电器
            {
                HAL_GPIO_WritePin(Relay_A_GPIO_Port, Relay_A_Pin, GPIO_PIN_SET);
            }
            else    // 关闭继电器
            {
                HAL_GPIO_WritePin(Relay_A_GPIO_Port, Relay_A_Pin, GPIO_PIN_RESET);
            }
            Relay.ucRelay_Status_Buf[RELAY_A] = status; // 更新继电器状态
            break;
        }
        case RELAY_B:
        {
            if (RELAY_ON == status) // 打开继电器
            {
                HAL_GPIO_WritePin(Relay_B_GPIO_Port, Relay_B_Pin, GPIO_PIN_SET);
            }
            else    // 关闭继电器
            {
                HAL_GPIO_WritePin(Relay_B_GPIO_Port, Relay_B_Pin, GPIO_PIN_RESET);
            }
            Relay.ucRelay_Status_Buf[RELAY_B] = status; // 更新继电器状态            
            break;
        }
        case RELAY_C:
        {
            if (RELAY_ON == status) // 打开继电器
            {
                HAL_GPIO_WritePin(Relay_C_GPIO_Port, Relay_C_Pin, GPIO_PIN_SET);
            }
            else    // 关闭继电器
            {
                HAL_GPIO_WritePin(Relay_C_GPIO_Port, Relay_C_Pin, GPIO_PIN_RESET);
            }
            Relay.ucRelay_Status_Buf[RELAY_C] = status; // 更新继电器状态            
            break;
        }
        case RELAY_D:
        {
            if (RELAY_ON == status) // 打开继电器
            {
                HAL_GPIO_WritePin(Relay_D_GPIO_Port, Relay_D_Pin, GPIO_PIN_SET);
            }
            else    // 关闭继电器
            {
                HAL_GPIO_WritePin(Relay_D_GPIO_Port, Relay_D_Pin, GPIO_PIN_RESET);
            }    
            Relay.ucRelay_Status_Buf[RELAY_D] = status; // 更新继电器状态        
            break;
        }
        default:break;
    }
}
IW_Dog.h
cpp
#ifndef __IW_DOG_H
#define __IW_DOG_H

typedef struct
{
    void (*IW_Dog_Init)(void);
	void (*IW_Dog_Feed)(void);
} IW_Dog_st;

extern IW_Dog_st IW_Dog;

#endif
IW_Dog.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
独立看门狗,定时2S --- (1/(40000/64)) * x = 2s  x = 1250
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private function prototypes===============================================*/
static void IW_Dog_Init(void);
static void IW_Dog_Feed(void);
/* Public variables==========================================================*/
IW_Dog_st IW_Dog = 
{
    .IW_Dog_Init = &IW_Dog_Init,
    .IW_Dog_Feed = &IW_Dog_Feed
};

/*
* @function: IW_Dog_Init
* @param: None
* @retval: None
* @brief: 独立看门狗初始化
*/
static void IW_Dog_Init(void)
{
    IW_Dog_Feed();
}

/*
* @function: IW_Dog_Feed
* @param: None
* @retval: None
* @brief: 喂狗
*/
static void IW_Dog_Feed(void)
{
    HAL_IWDG_Refresh(&hiwdg);   // 喂狗
}
Pwm_Led.h
cpp
#ifndef __PWM_LED_H
#define __PWM_LED_H

// LED灯带选择
typedef enum
{
    LED1 = 0x00,
    LED2 = 0x01,
    LED3 = 0x02,
    LED4 = 0x03
} Pwm_Led_Number_et;

typedef struct
{
    void (*Pwm_Led_Init)(void); // PWM灯带初始化
    void (*Pwm_Led_Duty_Control)(Pwm_Led_Number_et, uint8_t);    // PWM灯带占空比控制
    void (*Pwm_Led_Breathing)(Pwm_Led_Number_et); // 呼吸灯控制
} Pwm_Led_st;

extern Pwm_Led_st Pwm_Led;

#endif
Pwm_Led.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
LED灯带接线:
    PA8(TIM1_CH1) --- LED1
    PA9(TIM1_CH2) --- LED2
    PA10(TIM1_CH3) --- LED3
    PA11(TIM1_CH4) --- LED4
    定时器频率设置为1ms,ARR为100,占空比则是0~100对应0%~100%
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private variables=========================================================*/
static uint8_t Led_Duty[] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 101, 90, 80, 70, 60, 50, 40, 30, 20, 10};
/* Private function prototypes===============================================*/
static void Pwm_Led_Init(void);
static void Pwm_Led_Duty_Control(Pwm_Led_Number_et LEDx, uint8_t duty);
static void Pwm_Led_Breathing(Pwm_Led_Number_et LEDx);
/* Public variables==========================================================*/
Pwm_Led_st Pwm_Led = 
{
    .Pwm_Led_Init = &Pwm_Led_Init,
    .Pwm_Led_Duty_Control = &Pwm_Led_Duty_Control,
    .Pwm_Led_Breathing = &Pwm_Led_Breathing
};

/*
* @function: Pwm_Led_Init
* @param: None
* @retval: None
* @brief: LED灯带初始化
*/
static void Pwm_Led_Init(void)
{
    Pwm_Led_Duty_Control(LED1, 0);
    Pwm_Led_Duty_Control(LED2, 0);
    Pwm_Led_Duty_Control(LED3, 0);
    Pwm_Led_Duty_Control(LED4, 0);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
}

/*
* @function: Pwm_Led_Duty_Control
* @param: None
* @retval: None
* @brief: PWM灯带占空比控制
*/
static void Pwm_Led_Duty_Control(Pwm_Led_Number_et LEDx, uint8_t duty)
{
    switch (LEDx)
    {
        case LED1:
        {
            TIM1->CCR1 = duty;
            break;
        }
        case LED2:
        {
            TIM1->CCR2 = duty;
            break;
        }
        case LED3:
        {
            TIM1->CCR3 = duty;
            break;
        }
        case LED4:
        {
            TIM1->CCR4 = duty;
            break;
        }
        default:break;
    }
}

/*
* @function: Pwm_Led_Breathing
* @param: None
* @retval: None
* @brief: 呼吸灯控制
*/
static void Pwm_Led_Breathing(Pwm_Led_Number_et LEDx)
{
    static uint8_t Index1 = 0;
    static uint8_t Index2 = 0;
    static uint8_t Index3 = 0;
    static uint8_t Index4 = 0;
    uint8_t len = (sizeof(Led_Duty) / sizeof(Led_Duty[0])) - 1;   // 计算数组的长度

    switch (LEDx)
    {
        case LED1:
        {
            Pwm_Led_Duty_Control(LED1, Led_Duty[Index1]);
            Index1 = (Index1 - 0 + 1) % (len - 0 + 1) + 0;            
            break;
        }
        case LED2:
        {
            Pwm_Led_Duty_Control(LED2, Led_Duty[Index2]);
            Index2 = (Index2 - 0 + 1) % (len - 0 + 1) + 0;            
            break;
        }
        case LED3:
        {
            Pwm_Led_Duty_Control(LED3, Led_Duty[Index3]);
            Index3 = (Index3 - 0 + 1) % (len - 0 + 1) + 0;            
            break;
        }
        case LED4:
        {
            Pwm_Led_Duty_Control(LED4, Led_Duty[Index4]);
            Index4 = (Index4 - 0 + 1) % (len - 0 + 1) + 0;            
            break;
        }
        default:break;
    }
}
ultrasound.h
cpp
#ifndef __ULTRASOUND_H
#define __ULTRASOUND_H

// 打印调试使能
#define Ultrasound_Debug 0

/*触发引脚*/
// 置1
#define SOUND_Trig_1_Set() HAL_GPIO_WritePin(Sound_Trig_1_GPIO_Port, Sound_Trig_1_Pin, GPIO_PIN_SET)
// 置0
#define SOUND_Trig_1_RESET() HAL_GPIO_WritePin(Sound_Trig_1_GPIO_Port, Sound_Trig_1_Pin, GPIO_PIN_RESET)
// 超声波所用定时器
#define Ultrasound_Timer &htim2
// 超声波1所在通道
#define Ultrasound_Channel TIM_CHANNEL_1

typedef struct
{
    uint16_t distance;  // 测量距离
    uint32_t Timer_Cnt_Buf[3];  // 存放定时器计数数值的数组
    uint8_t Run_Status; // 运行到哪个步骤状态标志位
    uint32_t Hight_Time;    // 模块返回的高电平时间
    void (*ultrasound_Get_Value)(void);    // 超声波获取值
    void (*ultrasound_Handler)(void);  // 超声波处理函数
} ultrasound_st;

extern ultrasound_st ultrasound;
#endif
ultrasoud.c
cpp
/***************************************************************************
 * File: xxx.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
接线:
    PA4 --- Trig
    PA0(TIM2_CH1) --- Echo
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private function prototypes===============================================*/
static void ultrasound_Get_Value(void);
static void ultrasound_Handler(void);
/* Public variables==========================================================*/
ultrasound_st ultrasound = 
{
    .distance = 0,
    .Timer_Cnt_Buf = {0},
    .Run_Status = 0,
    .Hight_Time = 0,
    .ultrasound_Get_Value = &ultrasound_Get_Value,
    .ultrasound_Handler = &ultrasound_Handler
};

/*
* @function: ultrasound_Get_Value
* @param: None
* @retval: None
* @brief: 超声波获取值
*/
static void ultrasound_Get_Value(void)
{
    switch (ultrasound.Run_Status)
    {
        case 0:
        {
            SOUND_Trig_1_Set();
            Public.Public_Delay_us(30);
            SOUND_Trig_1_RESET();

            ultrasound.Run_Status++;
            __HAL_TIM_SET_CAPTUREPOLARITY(Ultrasound_Timer, Ultrasound_Channel, TIM_INPUTCHANNELPOLARITY_RISING);   // 上升沿触发
            HAL_TIM_IC_Start_IT(Ultrasound_Timer, Ultrasound_Channel);  // 输入捕获启动
            break;
        }
        case 3:
        {
            ultrasound.Hight_Time = ultrasound.Timer_Cnt_Buf[1] - ultrasound.Timer_Cnt_Buf[0];  // 计算高电平时间
            ultrasound.distance = (ultrasound.Hight_Time * 0.034) / 2;  // 单位cm
#if Ultrasound_Debug
            printf("Distance:%d\r\n", ultrasound.distance); // 打印距离
#endif            
            ultrasound.Run_Status = 0;  // 状态清0
            TIM2->CNT = 0;	// 计数值清0
            break;
        }
        default:break;
    }
}

/*
* @function: ultrasound_Handler
* @param: None
* @retval: None
* @brief: 超声波处理函数
*/
static void ultrasound_Handler(void)
{
    if (ultrasound.distance < 10)   // <10cm
    {
        Steer.Steer_Control(STEER_3, Angle_180);
    }
    else
    {
        Steer.Steer_Control(STEER_3, Angle_0);      
    }
}
Steer.h
cpp
#ifndef __STEER_H
#define __STEER_H

#define TIM4_ARR 200
// 0 --- 0.5ms 2.5%
#define Angle_0 (float)(0.025f * TIM4_ARR)
// 45 --- 1ms 5%
#define Angle_45 (float)(0.05f * TIM4_ARR)
// 90 --- 1.5ms 7.5%
#define Angle_90 (float)(0.075f * TIM4_ARR)
// 135 --- 2ms 10%
#define Angle_135 (float)(0.1f * TIM4_ARR)
// 180 --- 2.5ms 12.5%
#define Angle_180 (float)(0.125f * TIM4_ARR)

// 舵机复位
#define __Steer_Reset() do {    \
    Steer.Steer_Control(STEER_1, Angle_0);    \
    Steer.Steer_Control(STEER_2, Angle_0);    \
    Steer.Steer_Control(STEER_3, Angle_0);    \
    Steer.Steer_Control(STEER_4, Angle_0);    \
} while(0)

typedef enum
{
    STEER_1 = 0x00,
    STEER_2 = 0x01,    
    STEER_3 = 0x02,
    STEER_4 = 0x03,        
} Steer_Number_et;

typedef struct
{
    uint8_t Steer_Switch_Flag;
    void (*Steer_Init)(void);
	void (*Steer_Control)(Steer_Number_et, float);
    void (*Steer_Handler)(void);
} Steer_st;


extern Steer_st Steer;

#endif
Steer.c
cpp
/***************************************************************************
 * File: Steer.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
舵机接线:
        PB6(TIM4_CH1) --- 舵机1
        PB7(TIM4_CH2) --- 舵机2
        PB8(TIM4_CH3) --- 舵机3
        PB9(TIM4_CH4) --- 舵机4
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private function prototypes===============================================*/
static void Steer_Init(void);
static void Steer_Control(Steer_Number_et Steer_X, float angle);
static void Steer_Handler(void);
/* Public variables==========================================================*/
Steer_st Steer = 
{
    .Steer_Switch_Flag = FALSE,
    .Steer_Init = &Steer_Init,
	.Steer_Control = &Steer_Control,
    .Steer_Handler = &Steer_Handler
};

/*
* @function: Steer_Init
* @param: None
* @retval: None
* @brief: 舵机初始化
*/
static void Steer_Init(void)
{
    HAL_TIM_Base_Start(&htim4);
	
	Steer_Control(STEER_1, Angle_0);
	Steer_Control(STEER_2, Angle_0);
	Steer_Control(STEER_3, Angle_0);
	Steer_Control(STEER_4, Angle_0);
	
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);   // 通道1
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);   // 通道2
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);   // 通道3
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);   // 通道4
}

/*
* @function: Steer_Control
* @param: None
* @retval: None
* @brief: 舵机控制
*/
static void Steer_Control(Steer_Number_et Steer_X, float angle)
{
    switch (Steer_X)
    {
        case STEER_1:
        {
            TIM4->CCR1 = angle;
            break;
        }
        case STEER_2:
        {
			TIM4->CCR2 = angle;
            break;
        }
        case STEER_3:
        {
			TIM4->CCR3 = angle;
            break;
        }
        case STEER_4:
        {
			TIM4->CCR4 = angle;
            break;
        }
        default:break;                        
    }
}

/*
* @function: Steer_Handler
* @param: None
* @retval: None
* @brief: 舵机处理函数
*/
static void Steer_Handler(void)
{
    if (TRUE == Voice.Steer_Switch_Closure_Flag)    // 启动自动闭合
    {
        Steer.Steer_Switch_Flag = !Steer.Steer_Switch_Flag;

        if (Steer.Steer_Switch_Flag)
        {
            Steer_Control(STEER_1, Angle_180);
            Steer_Control(STEER_2, Angle_180);           
        }
        else
        {
            Steer_Control(STEER_1, Angle_0);
            Steer_Control(STEER_2, Angle_0);
        }        
    }
    else    // 关闭自动闭合
    {
        Steer_Control(STEER_1, Angle_0);
        Steer_Control(STEER_2, Angle_0);
    }
}

控制机械臂

  • 硬件

STM32F103C8T6

MG995舵机

【舵机】

  • 红色:5V
  • 粽色:GND
  • 橙色:PWM

【MG995舵机】

转动方向是 0°~180°,周期是 20ms(50Hz) 对应高电平时间是 0.5ms180° 对应高电平时间是 2.5ms

它步进值只能是 10°,小于 10° 没反应,可以通过公式计算出角度对应的周期时间:

比如当前需要转动到35°,则:(2.5-0.5)/180 * 35 + 0.5 = 0.88ms\text{比如当前需要转动到35°,则:(2.5-0.5)/180 * 35 + 0.5 = 0.88ms}

Steer.h
cpp
#ifndef __STEER_H
#define __STEER_H

// 舵机使用定时器
#define USE_STEER_Timer htim1

// 定时器ARR值
#define STEER_TIMER_ARR 200
// 最大周期(180°)
#define STEER_MAX_CYCLE 2.5f
// 最小周期(0°)
#define STEER_MIN_CYCLE 0.5f
// 最大可转角度
#define STEER_MAX_ANGLE 180
// 计算角度对应所需占空比值
#define STEER_CALCULATE_DUTY(angle) (uint8_t)((float)((STEER_MAX_CYCLE - STEER_MIN_CYCLE) / (float)STEER_MAX_ANGLE * angle + 0.5f) / 20 * 200)


// // 0 --- 0.5ms 2.5%   0.5/20=0.025
// #define Angle_0 (float)(0.025f * STEER_TIMER_ARR)
// // 45 --- 1ms 5%
// #define Angle_45 (float)(0.05f * STEER_TIMER_ARR)
// // 90 --- 1.5ms 7.5%
// #define Angle_90 (float)(0.075f * STEER_TIMER_ARR)
// // 135 --- 2ms 10%
// #define Angle_135 (float)(0.1f * STEER_TIMER_ARR)
// // 180 --- 2.5ms 12.5%
// #define Angle_180 (float)(0.125f * STEER_TIMER_ARR)

// 舵机复位
#define __Steer_Reset() do {    \
    Steer.Steer_Control(STEER_1, STEER_ANGLE_0);    \
    Steer.Steer_Control(STEER_2, STEER_ANGLE_0);    \
    Steer.Steer_Control(STEER_3, STEER_ANGLE_0);    \
    Steer.Steer_Control(STEER_4, STEER_ANGLE_0);    \
} while(0)
/*
角度--角度所需占空比值
0.0--5
10.0--6
20.0--7
30.0--8
40.0--9
50.0--10
60.0--11
70.0--12
80.0--13
90.0--15
100.0--16
110.0--17
120.0--18
130.0--19
140.0--20
150.0--21
160.0--22
170.0--23
180.0--25
*/
// 度数对应占空比值
typedef enum
{
    STEER_ANGLE_0 = (uint8_t)STEER_CALCULATE_DUTY(0),
    STEER_ANGLE_10 = (uint8_t)STEER_CALCULATE_DUTY(10),
    STEER_ANGLE_20 = (uint8_t)STEER_CALCULATE_DUTY(20),
    STEER_ANGLE_30 = (uint8_t)STEER_CALCULATE_DUTY(30),
    STEER_ANGLE_40 = (uint8_t)STEER_CALCULATE_DUTY(40),
    STEER_ANGLE_50 = (uint8_t)STEER_CALCULATE_DUTY(50),
    STEER_ANGLE_60 = (uint8_t)STEER_CALCULATE_DUTY(60),
    STEER_ANGLE_70 = (uint8_t)STEER_CALCULATE_DUTY(70),
    STEER_ANGLE_80 = (uint8_t)STEER_CALCULATE_DUTY(80),
    STEER_ANGLE_90 = (uint8_t)STEER_CALCULATE_DUTY(90),
    STEER_ANGLE_100 = (uint8_t)STEER_CALCULATE_DUTY(100),
    STEER_ANGLE_110 = (uint8_t)STEER_CALCULATE_DUTY(110),
    STEER_ANGLE_120 = (uint8_t)STEER_CALCULATE_DUTY(120),
    STEER_ANGLE_130 = (uint8_t)STEER_CALCULATE_DUTY(130),
    STEER_ANGLE_140 = (uint8_t)STEER_CALCULATE_DUTY(140),
    STEER_ANGLE_150 = (uint8_t)STEER_CALCULATE_DUTY(150),
    STEER_ANGLE_160 = (uint8_t)STEER_CALCULATE_DUTY(160),
    STEER_ANGLE_170 = (uint8_t)STEER_CALCULATE_DUTY(170),
    STEER_ANGLE_180 = (uint8_t)STEER_CALCULATE_DUTY(180)
} Steer_Angle_et;

typedef enum
{
    STEER_1 = 0,
    STEER_2 = 1,    
    STEER_3 = 2,
    STEER_4 = 3,
    MAX_STEER =  STEER_4 + 1,       
} Steer_Number_et;

typedef struct
{
    uint8_t Now_Angle; // 存储舵机当前的角度值
    uint16_t Turn_Time;  // 转动完所需时间(ms)大概2s
    uint8_t Turn_Over_Flag; // 转动计数完成标志位
} Steer_Parameter_st;

typedef struct
{
    uint8_t Steer_All_Start_Flag;   // 总启动标志位
    void (*Steer_Init)(void);
	uint8_t (*Steer_Control)(Steer_Number_et, Steer_Angle_et);
    void (*Steer_Test)(void);
    void (*Steer_Turn_Judge)(void);
} Steer_st;


extern Steer_st Steer;
extern Steer_Parameter_st Steer_Parameter[];

#endif
Steer.c
cpp
/***************************************************************************
 * File: Steer.c
 * Author: Yang
 * Date: 2023/11/21
 * description: 
 -----------------------------------
舵机接线:
        PA8(TIM1_CH1) --- 舵机1
        PA9(TIM1_CH2) --- 舵机2
        PA10(TIM1_CH3) --- 舵机3
        PA11(TIM1_CH4) --- 舵机4
 -----------------------------------
****************************************************************************/
#include "AllHead.h"

/* Private function prototypes===============================================*/
static void Steer_Init(void);
static uint8_t Steer_Control(Steer_Number_et Steer_X, Steer_Angle_et angle);
static void Steer_Test(void);
static void Steer_Turn_Judge(void);
/* Public variables==========================================================*/
Steer_Parameter_st Steer_Parameter[] = 
{
    {STEER_ANGLE_0, 2000, FALSE},
    {STEER_ANGLE_0, 2000, FALSE},
    {STEER_ANGLE_0, 2000, FALSE},
    {STEER_ANGLE_0, 2000, FALSE}
};

Steer_st Steer = 
{
    .Steer_All_Start_Flag = FALSE,
    .Steer_Init = &Steer_Init,
	.Steer_Control = &Steer_Control,
    .Steer_Test = &Steer_Test,
    .Steer_Turn_Judge = &Steer_Turn_Judge
};


/*
* @function: Steer_Init
* @param: None
* @retval: None
* @brief: 舵机初始化
*/
static void Steer_Init(void)
{
    HAL_TIM_Base_Start(&USE_STEER_Timer);
	
    __Steer_Reset();    // 复位
	
    HAL_TIM_PWM_Start(&USE_STEER_Timer, TIM_CHANNEL_1);   // 通道1
    HAL_TIM_PWM_Start(&USE_STEER_Timer, TIM_CHANNEL_2);   // 通道2
    HAL_TIM_PWM_Start(&USE_STEER_Timer, TIM_CHANNEL_3);   // 通道3
    HAL_TIM_PWM_Start(&USE_STEER_Timer, TIM_CHANNEL_4);   // 通道4
}

/*
* @function: Steer_Control
* @param: None
* @retval: None
* @brief: 舵机控制
*/
static uint8_t Steer_Control(Steer_Number_et Steer_X, Steer_Angle_et angle)
{
    uint8_t res = FALSE;
    uint8_t i;

    switch (Steer_X)
    {
        case STEER_1:
        {
            if (FALSE == Steer_Parameter[STEER_1].Turn_Over_Flag)
            {
                TIM1->CCR1 = angle;
                Steer_Parameter[STEER_1].Now_Angle = angle;
                Steer_Parameter[STEER_1].Turn_Over_Flag = TRUE;
                res = TRUE;
            }
            break;
        }
        case STEER_2:
        {
            if (FALSE == Steer_Parameter[STEER_2].Turn_Over_Flag)
            {
                TIM1->CCR2 = angle;
                Steer_Parameter[STEER_2].Now_Angle = angle;
                Steer_Parameter[STEER_2].Turn_Over_Flag = TRUE;
                res = TRUE;
            }
            break;
        }
        case STEER_3:
        {
            if (FALSE == Steer_Parameter[STEER_3].Turn_Over_Flag)
            {
                TIM1->CCR3 = angle;
                Steer_Parameter[STEER_3].Now_Angle = angle;
                Steer_Parameter[STEER_3].Turn_Over_Flag = TRUE;
                res = TRUE;
            }
            break;
        }
        case STEER_4:
        {
            if (FALSE == Steer_Parameter[STEER_4].Turn_Over_Flag)
            {
                TIM1->CCR4 = angle;
                Steer_Parameter[STEER_4].Now_Angle = angle;
                Steer_Parameter[STEER_4].Turn_Over_Flag = TRUE;
                res = TRUE;
            }            
            break;
        }
        default:break;                        
    }

    return res;
}

/*
* @function: Steer_Test
* @param: None
* @retval: None
* @brief: 舵机测试函数
*/
static void Steer_Test(void)
{
    static uint8_t step = 0;
    static Steer_Angle_et steer_angle_temp = STEER_ANGLE_0;

    if (!Steer.Steer_All_Start_Flag)    // 强制退出
    {
        return;
    }

    switch (step)
    {
        case 0: // 0 -> 180
        {
            Steer_Parameter[STEER_1].Turn_Time = 200; // 转小的度数
            if (steer_angle_temp != STEER_ANGLE_180)
            {
                if (TRUE == Steer.Steer_Control(STEER_1, steer_angle_temp))
                {
                    steer_angle_temp++;
                }
            }
            else
            {
                step++;
            }
            break;
        }
        case 1: // 180 -> 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
        {
            if (steer_angle_temp != STEER_ANGLE_0)
            {
                if (TRUE == Steer.Steer_Control(STEER_1, steer_angle_temp))
                {
                    steer_angle_temp--;
                }
            }
            else
            {
                step++;
            }
            break;
        }
        case 2: // 180
        {
            Steer_Parameter[STEER_1].Turn_Time = 2000; // 转大的度数
            if (TRUE == Steer.Steer_Control(STEER_1, STEER_ANGLE_180))
            {
                step++;
            }
            break;
        }
        case 3: // 180
        {
            if (TRUE == Steer.Steer_Control(STEER_1, STEER_ANGLE_0))
            {
                step = 0;
            }        
            break;
        }
        default:
        {
            step = 0;
            break;
        }      
    }
    return;
}

/*
* @function: Steer_Turn_Judge
* @param: None
* @retval: None
* @brief: 转向时间计数(1ms检测一次)
*/
static void Steer_Turn_Judge(void)
{
    uint8_t i;
    static uint16_t Steer_Turn_Cnt[MAX_STEER] = {0};

    for (i = 0; i < MAX_STEER; i++)
    {
        if (Steer_Parameter[i].Turn_Over_Flag)  // 置1
        {
            Steer_Turn_Cnt[i]++;
            if (Steer_Turn_Cnt[i] >= Steer_Parameter[i].Turn_Time)
            {
                Steer_Turn_Cnt[i] = 0;
                Steer_Parameter[i].Turn_Over_Flag = FALSE;
            }
        }
    }
}
CallBack.c
cpp
/***************************************************************************
 * File: CallBack.c
 * Author: Luckys.
 * Date: 2023/06/19
 * description: store interrupt function
****************************************************************************/
#include "AllHead.h"

/* Public variables==========================================================*/
extern uint8_t ucUart1_Rec_Buff[128];
/*
* @function: HAL_TIM_PeriodElapsedCallback
* @param: None
* @retval: None
* @brief: timer callback function
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == htim4.Instance) // 1ms
  {
    System.Task_Marks_Handler();
    Steer.Steer_Turn_Judge(); // 计数
  }
}

void USART1_IRQHandler(void)
{
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != 0x00u)
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
    	HAL_UART_DMAStop(&huart1);   // 串口停止DMA接收
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ1_0") != NULL)
		{
			Steer.Steer_Control(STEER_1, STEER_ANGLE_0);
      printf("1\r\n");
		}
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ1_45") != NULL)
		{
			Steer.Steer_Control(STEER_1, STEER_ANGLE_50);
      printf("1\r\n");
		}
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ1_90") != NULL)
		{
			Steer.Steer_Control(STEER_1, STEER_ANGLE_90);
      printf("1\r\n");
		}
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ1_135") != NULL)
		{
			Steer.Steer_Control(STEER_1, STEER_ANGLE_160);
      printf("1\r\n");
		}
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ1_180") != NULL)
		{
			Steer.Steer_Control(STEER_1, STEER_ANGLE_180);
      printf("1\r\n");
		}  
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ_CLOSE") != NULL) 
		{
      Steer.Steer_All_Start_Flag = FALSE;
		}         
		if (strstr((char*)ucUart1_Rec_Buff, (char*)"DJ_OPEN") != NULL) 
		{
      Steer.Steer_All_Start_Flag = TRUE;
		}              
    HAL_UART_Receive_DMA(&huart1, ucUart1_Rec_Buff, 128);    
	}
	
	HAL_UART_IRQHandler(&huart1);
}
Task.c
cpp
static inline void TasksHandle_200MS(void)
{
	HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
	Steer.Steer_Test();	// 测试
}