文章目录
23年嵌赛作品----智能送药小车
SmartCarV3.1
更新:
正式第一版-2023.6.16
改动避障及添加车灯-2023.7.7
增加串口屏与小车的交互及RTC-2023.7.10
终版一期:SmartCar-V2.4 2023.7.10
复赛完善终版二期:SmartCar-V3.0 2023.7.24
完善新一期:SmartCar-V3.1 2023.9.20
工程内容:
1.蓝牙控制小车行驶状态
2.超声波避障
3.舵机旋转超声波模块
4.串口屏人机交互
5.车辆指示灯
6.5路灰度传感器循迹
新期工程方案
1.避障:一个超声波和两红外对管避障
2.串口屏UI更改
3.一键更改操作模式
4.代码框架更新
引脚资源
电机PWM :
TIM15-PWM
PB14-TIM15_CH1-PWMR
PB15-TIM15_CH2-PWML
车轮:
PB1-MRP PB2-MRN
PB11-MLP PB12-MLN
蓝牙串口:
PC4-USART1_TX
PC5-USART1_RX
舵机:
TIM16-PWM
PA6-TIM16_CH1-PWM
超声波:
TIM6-计时
PC2-ECHO
PC3-TRIG
基本定时器:
TIM7-2ms定时器
TIM17-1s定时器
车辆指示灯:
PA0,PA1,PA4,PB0
串口屏
PB3-USART2_TX
PB4-USART2_RX
五路灰度传感器
PC11-R2
PC10-R1
PC12-MI
PA15-L1
PB7-L2
红外对管
PC6-IR333_R
PC7-IR333_L
CubeMX配置
时钟配置
基本定时器
TIM7-2ms定时器
TIM7参数设置
TIM7 NVIC
else if(tim_baseHandle->Instance==TIM7)
{
/* USER CODE BEGIN TIM7_MspInit 0 */
/* USER CODE END TIM7_MspInit 0 */
/* TIM7 clock enable */
__HAL_RCC_TIM7_CLK_ENABLE();
/* TIM7 interrupt Init */
HAL_NVIC_SetPriority(TIM7_DAC_IRQn, 2, 1);
HAL_NVIC_EnableIRQ(TIM7_DAC_IRQn);
TIM17-1s定时器
TIM17参数设置
TIM17 NVIC
else if(tim_baseHandle->Instance==TIM17)
{
/* USER CODE BEGIN TIM17_MspInit 0 */
/* USER CODE END TIM17_MspInit 0 */
/* TIM17 clock enable */
__HAL_RCC_TIM17_CLK_ENABLE();
/* TIM17 interrupt Init */
HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM17_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM17_IRQn);
RTC
电机PWM及车轮
PWMGPIO配置
PWMTIM配置
PWM NVIC off
车轮GPIO
蓝牙串口
USART NVIC
串口屏
USART NVIC
超声波
GPIO配置
TIM配置
TIM NVIC off
舵机
PWM
NVIC
车辆指示灯
GPIO配置
74HC4052驱动指示灯
五路灰度传感器
GPIO配置
红外对管
GPIO配置
修改:PC6-IR333R
PC7-IR333L
拉高,红外对管指示灯灭为高电平,灯亮为低电平
工程代码
main.c
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "my_Motor.h"
#include "c_ultrasonic.h"
#include "u_Timer.h"
#include "u_carled.h"
MOTOR_HandleTypeDef hmotor1 = {0};
static uint8_t reCmd = 0;
uint8_t USART_RX_BUF[USART_RX_BUF_SIZE];
uint8_t aRxBuffer[1];
uint16_t USART_RX_STA;
uint8_t Speed,Room,Start_Flag;
RTC_TimeTypeDef RTC_TimeStruct; //RTC时间
RTC_DateTypeDef RTC_DateStruct; //RTC日期
static void Proc1sTask(void);
static void Proc2msTask(void);
void LEDFlicker(uint16_t cnt);
static void UARTScreen_RX(void);
void CmdGroup(void); //驱动电机命令组
static void Get_Time_Date(uint16_t cnt);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM15_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
MX_TIM16_Init();
MX_TIM7_Init();
MX_TIM17_Init();
MX_LPUART1_UART_Init();
InitLED();
while (1)
{
Proc1sTask(); //1s任务
Proc2msTask(); //2ms任务
UARTScreen_RX(); //接收串口屏数据
}
}
static void Proc1sTask(void) //1s任务
{
if(Get1SecFlag())
{
Get_Time_Date(1);
CmdGroup(); //驱动电机命令组
Motor_Cmd(reCmd);
MotorSpeed_Cmd(); //电机速度控制
SetTurn(hmotor1.dir, hmotor1.PWMLValue, hmotor1.PWMRValue); //电机设置方向
Clr1SecFlag();
}
}
static void Proc2msTask(void) //2ms任务
{
if(Get2msFlag())
{
LEDFlicker(250); //500msLD2闪烁
Clr2msFlag();
}
}
void CmdGroup(void)
{
static uint8_t obstruction = 0x03; //通信标志位
static uint8_t BTCmd, AVCmd; //蓝牙命令 避障命令
AVCmd = Avoidance(); //每1s接收一次避障命令
if(obstruction & 0x03) //有障碍且在后左或右转向时接收该命令
{
if(AVCmd == 'Z' || AVCmd == 'X')
{
reCmd = AVCmd;
obstruction = 0x02;
}
}
if(obstruction == 0x02) //避开障碍直行
{
if(AVCmd == 'w')
{
reCmd = AVCmd;
obstruction = 0x01;
}
}
if(obstruction & 0x01)
{
BTCmd = BuleTeeth_Receive(); //接收蓝牙命令
if(BTCmd != 0) //接到正确的指令后锁住指令,当下次碰到障碍或接到正确的蓝牙指令后解锁
{
reCmd = BTCmd;
obstruction = 0x03;
}
BTCmd = 0;
}
}
void LEDFlicker(uint16_t cnt) //板载LED闪烁
{
static uint16_t s_iCnt; //定义静态变量s_iCnt作为计数器
s_iCnt++; //计数器的计数值加1
if(s_iCnt >= cnt) //计数器的计数值大于cnt
{
s_iCnt = 0; //重置计数器的计数值为0
LED_Cmd(reCmd); //指示灯命令
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}
}
main.h
#define USART_RX_BUF_SIZE 100
extern uint8_t USART_RX_BUF[USART_RX_BUF_SIZE];
extern uint8_t aRxBuffer[1];
extern uint16_t USART_RX_STA;
extern uint8_t arrBuffer[1]; //串口接收数据缓冲区
extern uint8_t arrU2Buffer[1];
extern uint8_t arrLPBuffer[1];
//extern uint8_t garrRx[20]; //串口接收的总数据
extern uint16_t gRxSTA; //串口接收到数据标志长度,0为false,1为true
extern uint8_t pro1sflag;
extern float nowdistance[3];
extern UART_HandleTypeDef huart1;
extern TIM_HandleTypeDef htim16;
extern TIM_HandleTypeDef htim15;
extern TIM_HandleTypeDef htim7;
extern TIM_HandleTypeDef htim6;
#define ECHO_Pin GPIO_PIN_2
#define ECHO_GPIO_Port GPIOC
#define TRIG_Pin GPIO_PIN_3
#define TRIG_GPIO_Port GPIOC
#define HC4052_A0_Pin GPIO_PIN_0
#define HC4052_A0_GPIO_Port GPIOA
#define HC4052_A1_Pin GPIO_PIN_1
#define HC4052_A1_GPIO_Port GPIOA
#define HC4052_X_Pin GPIO_PIN_4
#define HC4052_X_GPIO_Port GPIOA
#define LD2_Pin GPIO_PIN_5
#define LD2_GPIO_Port GPIOA
#define HC4052_Y_Pin GPIO_PIN_0
#define HC4052_Y_GPIO_Port GPIOB
#define MRP_Pin GPIO_PIN_1
#define MRP_GPIO_Port GPIOB
#define MRN_Pin GPIO_PIN_2
#define MRN_GPIO_Port GPIOB
#define MLP_Pin GPIO_PIN_11
#define MLP_GPIO_Port GPIOB
#define MLN_Pin GPIO_PIN_12
#define MLN_GPIO_Port GPIOB
#define PWMR_Pin GPIO_PIN_14
#define PWMR_GPIO_Port GPIOB
#define PWML_Pin GPIO_PIN_15
#define PWML_GPIO_Port GPIOB
前台框架
stm32g4xx_it.c
/* USER CODE BEGIN Includes */
#include "u_Timer.h"
/* USER CODE END Includes */
void TIM1_TRG_COM_TIM17_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 0 */
/* USER CODE END TIM1_TRG_COM_TIM17_IRQn 0 */
HAL_TIM_IRQHandler(&htim17);
/* USER CODE BEGIN TIM1_TRG_COM_TIM17_IRQn 1 */
static uint16_t s_cnt1s;
if(__HAL_TIM_GET_ITSTATUS(&htim17, TIM_IT_UPDATE) == SET) //定时器17中断更新
{
__HAL_TIM_CLEAR_IT(&htim17, TIM_FLAG_UPDATE); //清除中断更新标志位
}
s_cnt1s++; //1s计时
if(s_cnt1s >= 999)
{
s_cnt1s = 0;
s_1sFalg = TURE; //1s标志置位
}
/* USER CODE END TIM1_TRG_COM_TIM17_IRQn 1 */
}
void TIM7_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM7_DAC_IRQn 0 */
/* USER CODE END TIM7_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* USER CODE BEGIN TIM7_DAC_IRQn 1 */
static uint16_t s_cnt2ms;
if(__HAL_TIM_GET_ITSTATUS(&htim7, TIM_IT_UPDATE) == SET)
{
__HAL_TIM_CLEAR_IT(&htim7, TIM_FLAG_UPDATE);
}
s_cnt2ms++;
if(s_cnt2ms >= 2)
{
s_cnt2ms = 0;
s_2msFalg = TURE;
}
/* USER CODE END TIM7_DAC_IRQn 1 */
}
u_Timer.h
#ifndef _U_TIMER_H_
#define _U_TIMER_H_
#include "main.h"
extern uint8_t s_2msFalg;
extern uint8_t s_1sFalg;
typedef enum
{
FALSE = 0,
TURE
}E3_MODE;
uint8_t Get2msFlag(void); //获取2ms标志位的值
void Clr2msFlag(void); //清除2ms标志位
uint8_t Get1SecFlag(void); //获取1s标志位的值
void Clr1SecFlag(void); //清除1s标志位
#endif //_U_TIMER_H_
u_Timer.c
#include "u_Timer.h"
uint8_t s_2msFalg;
uint8_t s_1sFalg;
uint8_t Get2msFlag(void)
{
return s_2msFalg;
}
void Clr2msFlag(void)
{
s_2msFalg = FALSE; //2ms标志位复位
}
uint8_t Get1SecFlag(void)
{
return s_1sFalg;
}
void Clr1SecFlag(void)
{
s_1sFalg = FALSE; //1s标志位复位
}
蓝牙串口
//usart1.c
void MX_USART1_UART_Init(void)
{
/* MX CODE BEGIN */
//。。。。。。。。
/* MX CODE END */
/* USER CODE BEGIN */
HAL_UART_Receive_IT(&huart1, arrBuffer, 1);
/* USER CODE END */
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1); //这里会失能调用串口
while(HAL_UART_Receive_IT(&huart1, arrBuffer, 1) != HAL_OK) //所以这里要重新使能,同时接收
{
//当接收错误会卡死在这
}
}
//usart1.c
/* USER CODE BIGIN */
#define ARR_RX_MAX 20
uint8_t arrBuffer[1]; //串口接收数据缓冲区
uint8_t garrRx[20]; //串口接收的总数据
uint16_t gRxSTA; //串口接收到数据标志长度,0为false,1为true
//中断回调函数 二选一
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
gRxSTA = 1;
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
if((gRxSTA & 0x8000) == 0) //接收未完成
{
if(gRxSTA&0x4000) //接到了0x0d (\n)
{
// if(arrBuffer[0]!=0x0a) gRxSTA=0;//接收错误,重新开始 (\r)
gRxSTA |= 0x8000;
}
else //没接到0x0d
{
if(arrBuffer[0] == 0x0d) gRxSTA |= 0x4000;
else
{
garrRx[gRxSTA&0x3fff]=arrBuffer[0];
gRxSTA++;
if(gRxSTA>(ARR_RX_MAX-1)) gRxSTA=0; //接收溢出,重新接收
}
}
}
}
}
/* USER CODE END */
电机驱动
电机PWM
//tim.c
void MX_TIM15_Init(void)
{
/* MX CODE BEGIN */
//。。。。。。。。。
/* MX CODE BEGIN */
/* USER CODE BEGIN */
//PWM通道使能
HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim15, TIM_CHANNEL_1);
/* USER CODE END */
}
My_Motor.h
#ifndef _MY_MOTOR_H_
#define _MY_MOTOR_H_
#include "main.h"
#define MOTOR_Port GPIOB
typedef struct
{
uint8_t dir;
uint8_t mode;
uint16_t PWMRValue;
uint16_t PWMLValue;
}MOTOR_HandleTypeDef;
typedef enum
{
MODE_aSTOP = 0,
MODE_UPSPEED,
MODE_DECELERATE,
MODE_MAX
}E1_Mode;
typedef enum
{
DIR_GO = 0,
DIR_BACK,
DIR_GOLEFT,
DIR_GORIGHT,
DIR_BACKLEFT,
DIR_BACKRIGHT,
DIR_MAX
}E2_DIR;
extern MOTOR_HandleTypeDef hmotor1;
void SetTurn(uint8_t dir, uint16_t pwml, uint16_t pwmr);
void SetPWM(uint16_t pwm, uint8_t channle);
uint8_t BuleTeeth_Receive(void);
void Motor_Cmd(uint8_t reCmd);
#endif
My_Motor.c
#include "my_Motor.h"
//控制电机转向
void SetTurn(uint8_t dir, uint16_t pwml, uint16_t pwmr)
{
switch(dir)
{
case DIR_GO:
HAL_GPIO_WritePin(MOTOR_Port, MLP_Pin|MRP_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MLN_Pin|MRN_Pin, GPIO_PIN_RESET);
break;
case DIR_BACK:
HAL_GPIO_WritePin(MOTOR_Port, MRN_Pin|MLN_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MRP_Pin|MLP_Pin, GPIO_PIN_RESET);
break;
case DIR_GOLEFT:
HAL_GPIO_WritePin(MOTOR_Port, MRP_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MRN_Pin|MLP_Pin|MLN_Pin, GPIO_PIN_RESET);
break;
case DIR_GORIGHT:
HAL_GPIO_WritePin(MOTOR_Port, MLP_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MRN_Pin|MRP_Pin|MLN_Pin, GPIO_PIN_RESET);
break;
case DIR_BACKLEFT:
HAL_GPIO_WritePin(MOTOR_Port, MRN_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MRP_Pin|MLN_Pin|MLP_Pin, GPIO_PIN_RESET);
break;
case DIR_BACKRIGHT:
HAL_GPIO_WritePin(MOTOR_Port, MLN_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(MOTOR_Port, MRN_Pin|MRP_Pin|MLP_Pin, GPIO_PIN_RESET);
break;
}
SetPWM(pwmr,TIM_CHANNEL_1);
SetPWM(pwml,TIM_CHANNEL_2);
}
//开环控制电机速度
void SetPWM(uint16_t pwm, uint8_t channle)
{
__HAL_TIM_SET_COMPARE(&htim15, channle, pwm);
}
void Motor_Cmd(uint8_t reCmd)
{
if(reCmd == 'W') //前进
{
hmotor1.dir = DIR_GO;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 1100;
hmotor1.PWMLValue = 1000;
}
else if(reCmd == 'S') //后退
{
hmotor1.dir = DIR_BACK;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 1500;
hmotor1.PWMLValue = 1450;
}
else if(reCmd == '1') //停止
{
hmotor1.dir = DIR_GO;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 0;
hmotor1.PWMLValue = 0;
}
else if(reCmd == 'A') //左转
{
hmotor1.dir = DIR_GOLEFT;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 1500;
hmotor1.PWMLValue = 0;
}
else if(reCmd == 'D') //右转
{
hmotor1.dir = DIR_GORIGHT;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 0;
hmotor1.PWMLValue = 1500;
}
else if(reCmd == 'Z') //后左
{
hmotor1.dir = DIR_BACKLEFT;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 1500;
hmotor1.PWMLValue = 0;
}
else if(reCmd == 'X') //后右
{
hmotor1.dir = DIR_BACKRIGHT;
hmotor1.mode = MODE_aSTOP;
hmotor1.PWMRValue = 0;
hmotor1.PWMLValue = 1500;
}
else if(reCmd == 'U') //加速
{
hmotor1.mode = MODE_UPSPEED;
}
else if(reCmd == 'J') //减速
{
hmotor1.mode = MODE_DECELERATE;
}
}
uint8_t BuleTeeth_Receive(void)
{
uint8_t temp;
if(gRxSTA == 1) //接收成功,发送接收的数据
{
temp = arrBuffer[0];
arrBuffer[0] = 0;
gRxSTA = 0;
}
return temp;
}
void MotorSpeed_Cmd(void)
{
if(hmotor1.mode == MODE_UPSPEED)
{
hmotor1.PWMLValue += 100;
hmotor1.PWMRValue += 100;
if(hmotor1.PWMLValue >= 4000) hmotor1.PWMLValue = 4000;
if(hmotor1.PWMRValue >= 4000) hmotor1.PWMRValue = 4000;
HAL_Delay(200);
}
if(hmotor1.mode == MODE_DECELERATE)
{
hmotor1.PWMLValue -= 100;
hmotor1.PWMRValue -= 100;
if(hmotor1.PWMLValue <= 1000) hmotor1.PWMLValue = 1000;
if(hmotor1.PWMRValue <= 1000) hmotor1.PWMRValue = 1000;
HAL_Delay(200);
}
}
超声波
//tim.c文件
void MX_TIM6_Init(void)
{
/* MX CODE BEGIN */
//。。。。。。。。
/* MX CODE END */
/* USER CODE BEGIN */
HAL_TIM_Base_Start_IT(&htim6); //使能定时器更新中断
/* USER CODE END */
}
测距及避障
c_ultrasonic.h
#ifndef _C_ULTRASONIC_H_
#define _C_ULTRASONIC_H_
#include "main.h"
float Get_Distance(TIM_HandleTypeDef* htim); //超声波测距
void Servo(uint8_t angle); //舵机转向
uint8_t Avoidance(void); //避障
#endif
c_ultrasonic.c
#include "c_ultrasonic.h"
#include "my_Motor.h"
float nowdistance[3] = {25, 25, 25};
uint8_t Avoid_Front(void);
uint8_t Avoid_Left(void);
uint8_t Avoid_Right(void);
//返回值为距离,单位为cm
// 参数为定时器句柄,可自由选择空闲的定时器
float Get_Distance(TIM_HandleTypeDef *htim) // 超声波使用到的定时器。
{
unsigned int x1,x2; //接收端高电平起始、结束时定时器的计数值
float Distance; //定义距离
htim->Instance->CNT = 0; //清空定时器计数值
HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_SET); //开始测距,将TRIG拉高
HAL_Delay(1); //保持高电平10us以上
HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET); //将TRIG拉低
while(HAL_GPIO_ReadPin(ECHO_GPIO_Port,ECHO_Pin) == 0); //等待ECHO的高电平起始时间
x1 = htim->Instance->CNT;
while(HAL_GPIO_ReadPin(ECHO_GPIO_Port,ECHO_Pin) == 1); //记录ECHO高电平结束时间
x2 = htim->Instance->CNT;
htim->Instance->CNT = 0; //
Distance = (x2-x1)*0.017 ; //计算距离,单位为cm
return Distance;
}
uint8_t Avoid_Front(void)
{
uint8_t cmd = '0';
if(nowdistance[1] <=15)
{
cmd = '1';
}
else if(nowdistance[1] >=25)
{
cmd = 'w';
}
return cmd;
}
uint8_t Avoid_Left(void)
{
uint8_t cmd = '0';
if(nowdistance[2] <=15)
{
cmd = '1';
}
else if(nowdistance[2] >=25)
{
cmd = 'X';
}
return cmd;
}
uint8_t Avoid_Right(void)
{
uint8_t cmd = '0';
if(nowdistance[0] <=15)
{
cmd = '1';
}
else if(nowdistance[0] >=25)
{
cmd = 'Z';
}
return cmd;
}
uint8_t Avoidance(void)
{
uint8_t cmd[3] = {0,0,0};
uint8_t LastCmd = '0';
Servo(15);
cmd[1] = Avoid_Front();
if(cmd[1] == '1')
{
Servo(20);
PrintfDebug("%c\n\r", cmd[2]);
cmd[2] = Avoid_Left();
if(cmd[2] == 'X')
{
LastCmd = cmd[2];
}
else if(cmd[2] == '1')
{
Servo(10);
cmd[0] = Avoid_Right();
if(cmd[0] == 'Z')
{
LastCmd = cmd[0];
}
else if(cmd[0] == '1')
{
LastCmd = 'Z';
}
}
}
else if(cmd[1] == 'w')
{
LastCmd = cmd[1];
}
return LastCmd;
}
舵机
//tim.c
void MX_TIM16_Init(void)
{
/* MX CODE BEGIN */
//。。。。。。。。。
/* MX CODE BEGIN */
/* USER CODE BEGIN */
//PWM通道使能
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&htim16);
/* USER CODE END */
}
c_ultrasonic.c
void Servo(uint8_t angle) //舵机转向 5 10 15 20 25
{
__HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, angle);
if(angle == 15)
{
nowdistance[1] = Get_Distance(&htim6);
}
else if(angle == 10)
{
nowdistance[0] = Get_Distance(&htim6);
}
else if(angle == 20)
{
nowdistance[2] = Get_Distance(&htim6);
}
}
车辆指示灯
u_carled.h
#ifndef __U_CARLED_H_
#define __U_CARLED_H_
#include "main.h"
#define HC4052_A0(x) do{ x ? \
HAL_GPIO_WritePin(HC4052_A0_GPIO_Port, HC4052_A0_Pin, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(HC4052_A0_GPIO_Port, HC4052_A0_Pin, GPIO_PIN_RESET); \
}while(0)
#define HC4052_A1(x) do{ x ? \
HAL_GPIO_WritePin(HC4052_A1_GPIO_Port, HC4052_A1_Pin, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(HC4052_A1_GPIO_Port, HC4052_A1_Pin, GPIO_PIN_RESET); \
}while(0)
#define HC4052_X(x) do{ x ? \
HAL_GPIO_WritePin(HC4052_X_GPIO_Port, HC4052_X_Pin, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(HC4052_X_GPIO_Port, HC4052_X_Pin, GPIO_PIN_RESET); \
}while(0)
#define HC4052_Y(x) do{ x ? \
HAL_GPIO_WritePin(HC4052_Y_GPIO_Port, HC4052_Y_Pin, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(HC4052_Y_GPIO_Port, HC4052_Y_Pin, GPIO_PIN_RESET); \
}while(0)
void LED_Cmd(uint8_t reCmd);
void InitLED(void);
#endif // __U_CARLED_H_
u_carled.c
#include "u_carled.h"
void SelectLED(uint8_t led);
void TurnLED(uint8_t led);
void SignalLED(uint8_t led);
void InitLED(void)
{
HC4052_X(1);
HC4052_Y(1);
}
void SelectLED(uint8_t led)
{
switch(led)
{
case 1:HC4052_A0(0);HC4052_A1(0); //左转信号
break;
case 2:HC4052_A0(1);HC4052_A1(0); //右转信号
break;
case 3:HC4052_A0(0);HC4052_A1(1); //后右转信号
break;
case 4:HC4052_A0(1);HC4052_A1(1); //后左转信号
break;
default:HC4052_X(1);HC4052_Y(1);
break;
}
}
void TurnLED(uint8_t led) //led:1 2 3 4
{
SelectLED(led);
if(led != 0)
{
HAL_GPIO_TogglePin(HC4052_X_GPIO_Port, HC4052_X_Pin);
HC4052_Y(1);
}
else
{
HC4052_X(1);
HC4052_Y(1);
}
}
void SignalLED(uint8_t led) //led:1 2 3
{
SelectLED(led);
if(led != 0)
{
HAL_GPIO_TogglePin(HC4052_Y_GPIO_Port, HC4052_Y_Pin);
HC4052_X(1);
}
else
{
HC4052_X(1);
HC4052_Y(1);
}
}
void LED_Cmd(uint8_t reCmd)
{
if(reCmd == 'A')
{
TurnLED(1);
}
else if(reCmd == 'D')
{
TurnLED(2);
}
else if(reCmd == 'X')
{
TurnLED(3);
}
else if(reCmd == 'Z')
{
TurnLED(4);
}
else if(reCmd == 'S')
{
SignalLED(3);
}
else if(reCmd == '1')
{
SignalLED(2);
}
else if(reCmd == 'w' || reCmd == 'W')
{
TurnLED(0);
SignalLED(0);
}
}
RTC
static void Get_Time_Date(uint16_t cnt) //获取RTC时间日期
{
static uint16_t s_iCnt;
// PrintfDebug("2MSTask\r\n");
s_iCnt++;
if(s_iCnt >= cnt)
{
s_iCnt = 0;
HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
Printf("main.Time.txt=\"%d:%d\"\xff\xff\xff", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes);
Printf("main.Date.txt=\"\%d月%d号星期%d \"\xff\xff\xff", RTC_DateStruct.Month, RTC_DateStruct.Date, RTC_DateStruct.WeekDay);
}
}
串口屏
USART2
usart.c
void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 2 */
HAL_UART_Receive_IT(&huart2, aRxBuffer, 1);
/* USER CODE END USART2_Init 2 */
}
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
while(HAL_UART_Receive_IT(&huart2, aRxBuffer, 1) != HAL_OK) //所以这里要重新使能,同时接收
{
//当接收错误会卡死在这
}
/* USER CODE END USART2_IRQn 1 */
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
gRxSTA = 1;
}
if(huart->Instance == USART2)
{
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
USART_RX_STA++;
if(USART_RX_STA>(USART_RX_BUF_SIZE-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
if(huart->Instance == LPUART1)
{
gRxSTA = 1;
}
}
重定向
u_print.c
#include "u_print.h"
#include "stdint.h"
#include "stdarg.h"
#include "stdio.h"
#include "usart.h"
#define CONSOLEBUF_SIZE 64
void Printf(const char *fmt, ...)
{
char Uart_buf[CONSOLEBUF_SIZE];
uint16_t len = 0;
va_list args;
va_start(args, fmt);
len = vsprintf(Uart_buf, fmt, args);
va_end(args);
HAL_UART_Transmit(&huart2, (uint8_t *)Uart_buf, len, 0xf);
}
接收处理USART2
static void UARTScreen_RX(void)
{
uint8_t len;
if(USART_RX_STA&0x8000)
{
reCmd = 0;
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 //按下开始健发送速度、药品、开始信息,长度为4
if(len==4&&USART_RX_BUF[0] == 0x33)
{
Speed = USART_RX_BUF[1]; //速度
Room = USART_RX_BUF[2]; //病房号
Start_Flag = USART_RX_BUF[3]; //开始信息
switch(Speed)
{
case 0: hmotor1.PWMLValue = 0;hmotor1.PWMRValue = 0;
break;
case 1:hmotor1.PWMLValue = 1000;hmotor1.PWMRValue = 1100;
break;
case 2:hmotor1.PWMLValue = 1900;hmotor1.PWMRValue = 2000;
break;
case 3:hmotor1.PWMLValue = 2800;hmotor1.PWMRValue = 2900;
break;
case 4:hmotor1.PWMLValue = 3800;hmotor1.PWMRValue = 3900;
break;
case 5:hmotor1.PWMLValue = 4800;hmotor1.PWMRValue = 4950;
break;
default:
break;
}
switch(Room)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6://PrintfDebug("Room = %d\r\n", Room);
break;
default:
break;
}
if(Room == 4)
{
PrintfDebug("Room = %d\r\n", Room);
}
if(Start_Flag == 'W')
{
hmotor1.dir = DIR_GO;
}
}
if(len==2&&USART_RX_BUF[0] == 0x33)
{
Start_Flag = USART_RX_BUF[1];
if(Start_Flag == '1')
{
hmotor1.PWMLValue = 0;hmotor1.PWMRValue = 0;
}
}
USART_RX_STA=0;
}
}
五路灰度传感器
u_track.h
#ifndef _U_TRACK_H_
#define _U_TRACK_H_
#include "main.h"
#include "u_print.h"
#define TRACK_R2_Pin GPIO_PIN_11 //GPIOC
#define TRACK_R1_Pin GPIO_PIN_10 //GPIOC
#define TRACK_MI_Pin GPIO_PIN_12 //GPIOC
#define TRACK_L1_Pin GPIO_PIN_15 //GPIOA
#define TRACK_L2_Pin GPIO_PIN_7 //GPIOB
#define TRACK_R2() (HAL_GPIO_ReadPin(GPIOC, TRACK_R2_Pin))
#define TRACK_R1() (HAL_GPIO_ReadPin(GPIOC, TRACK_R1_Pin))
#define TRACK_MI() (HAL_GPIO_ReadPin(GPIOC, TRACK_MI_Pin))
#define TRACK_L1() (HAL_GPIO_ReadPin(GPIOA, TRACK_L1_Pin))
#define TRACK_L2() (HAL_GPIO_ReadPin(GPIOB, TRACK_L2_Pin))
typedef enum
{
LowLevel = GPIO_PIN_RESET,
HightLevel = GPIO_PIN_SET,
LevelMAX = 2
}EnumLevel;
uint8_t RedW_Track(void);
uint8_t RedW_TrackRoom(uint8_t room);
#endif //_U_TRACK_H_
u_track.c
#include "u_track.h"
uint8_t RedW_Track(void)
{
uint8_t s_iTrackCmd = '0'; //传给电机的命令
static uint8_t s_iTrackFlag = 0x00; //循迹电平标志
if(TRACK_MI() == LowLevel) s_iTrackFlag |= 0x02; //寻到黑线时将对应标志位置位
else if(TRACK_MI() == HightLevel) s_iTrackFlag &= (~0x02);
if(TRACK_R1() == LowLevel) s_iTrackFlag |= 0x01; //D
else if(TRACK_R1() == HightLevel) s_iTrackFlag &= ~0x01;
if(TRACK_L1() == LowLevel) s_iTrackFlag |= 0x04; //A
else if(TRACK_L1() == HightLevel) s_iTrackFlag &= ~0x04;
if(s_iTrackFlag == 0x02 || s_iTrackFlag == 0x06) //中线寻到
{
s_iTrackCmd = 'w';
}
// else if(s_iTrackFlag == 0x01) //右边寻到
// {
// s_iTrackCmd = 'D';
// }
// else if(s_iTrackFlag == 0x04) //左边寻到
// {
// s_iTrackCmd = 'A';
// }
else if(s_iTrackFlag == 0x00) //没寻到
{
s_iTrackCmd = '0';
}
PrintfDebug("Cmd = %c\r\n", s_iTrackCmd);
PrintfDebug("Flag = %d\r\n", s_iTrackFlag);
return s_iTrackCmd;
}
uint8_t RedW_TrackRoom(uint8_t room)
{
uint8_t s_iTrackCmd = '0'; //传给电机的命令
static uint8_t s_iTrackFlag = 0x00; //循迹电平标志
static uint8_t s_iRoomCnt;
if(TRACK_MI() == LowLevel) s_iTrackFlag |= 0x02; //寻到黑线时将对应标志位置位
else if(TRACK_MI() == HightLevel) s_iTrackFlag &= ~0x02;
if(TRACK_R1() == LowLevel) s_iTrackFlag |= 0x01;
else if(TRACK_R1() == HightLevel) s_iTrackFlag &= ~0x01;
if(TRACK_L1() == LowLevel) s_iTrackFlag |= 0x04;
else if(TRACK_L1() == HightLevel) s_iTrackFlag &= ~0x04;
if(TRACK_L2() == LowLevel) s_iTrackFlag |= 0x08;
else if(TRACK_L1() == HightLevel) s_iTrackFlag &= ~0x08;
if(TRACK_R2() == LowLevel) s_iTrackFlag |= 0x10;
else if(TRACK_L1() == HightLevel) s_iTrackFlag &= ~0x10;
if(s_iTrackFlag == 0x1f)
{
s_iRoomCnt++;
if(s_iRoomCnt == ((room+1) / 2))
{
switch(room)
{
case 1:
case 3:
case 5:s_iTrackCmd = 'A'; PrintfDebug("YES\r\n");
break;
case 2:
case 4:
case 6:s_iTrackCmd = 'D';PrintfDebug("NO\r\n");
break;
default:
break;
}
s_iRoomCnt = 0;
}
else s_iTrackCmd = '0';
}
return s_iTrackCmd;
}
循迹
static uint8_t s_iRoomNum = 0x00;
static uint8_t s_iRoomFlag = 0x00;
static uint8_t s_ihTrackFlag = 0x00;
void TrackCmd(void)
{
if(s_ihTrackFlag == 0x01)
{
if(reCmd == 'A' || reCmd == 'D')
{
if(RedW_Track() != '0')
{
reCmd = RedW_Track();
}
PrintfDebug("3reCmd = %c\r\n", reCmd);
}
if(reCmd == 'w')
{
if(RedW_Track() == '0')
{
reCmd = '1';
PrintfDebug("4reCmd = %c\r\n", reCmd);
}
}
if(s_iRoomFlag == 0x01)
{
if(RedW_TrackRoom(s_iRoomNum) != '0')
{
reCmd = RedW_TrackRoom(s_iRoomNum);
PrintfDebug("1reCmd = %c\r\n", reCmd);
s_iRoomFlag = 0x00;
}
PrintfDebug("2reCmd = %c\r\n", reCmd);
}