单片机mian主逻辑的写法
双while(1)写法
在嵌入式系统编程中,尤其是在使用C语言编写的程序中,while(1) 循环通常用于创建一个无限循环,这样程序就可以持续运行,不会自行终止。
这种结构在嵌入式应用程序中非常常见,因为它们通常需要不断地响应外部事件,如用户输入、传感器数据或其他设备通信。
在您提供的 MODE_2 函数中,也包含了一个 while(1) 循环。这是因为 MODE_2是一个特定的模式,它需要在自己的函数中持续运行,直到被外部事件(如用户按下特定的键)中断,通过retrun跳出mode_2()。即使这个函数被包含在主程序的while(1) 循环中调用,它仍然需要自己的循环来处理该模式下的所有逻辑。 这里的结构是这样的:
1.主程序的 while(1)循环:这是程序的最外层循环,它不断地检查当前的模式(由 MEMU 变量控制),并调用相应的模式处理函数(如 MODE_1, MODE_2,MODE_3, MODE_4 等)。
2.模式函数内的 while(1) 循环:每个模式函数(如 MODE_2)内部也有自己的 while(1)循环。这个循环负责处理该模式下的所有逻辑,如读取传感器数据、更新显示、处理用户输入等。当需要退出该模式时(例如用户按下了返回键),函数会设置MEMU 变量到一个特定的值,这样主程序的 while(1) 循环就会调用另一个模式处理函数或退出当前模式。
------------------------主程序部分main.py----------------------------------------
int main (void)
{
RCC_Configuration(); //时钟设置
NVIC_Configuration(); //NVIC设置
//串口通信部分
uart1_init(9600);//连接昆仑屏——485
uart2_init(115200); //连接摄像头板
uart3_init(9600); //连接语音板
uart4_init(9600);//连接电视板
uart5_init(115200);//连接舵机板
TIM3_Int_Init(3600-1,10000-1); //定时周期500ms,用于各种计时
//RTC部分
RTC_Config();//初始化RTC时钟
BKP_Configuration();//初始化BKP
RTC_Set(2023,9,26,10,30,20); //设置当前时间
//显示部分
LCD_Init();//LCD初始化
LCD_Clear();
KEYPAD5x4_Init(); //矩阵键盘初始化
EXTIX_Init();//外部中断 初始化
Relay_Init();//继电器初始化
//云台部分
Store_Init();
bsp_Coordinate_instructions((float)(0),(float)(-19.5));//舵机初始化——复位到指定位置
while(1)
{
switch(MEMU) //判断MEMU值,执行对应模式函数
{
case 0: LCD_Start();break; //初始等待界面
case 1: LCD_Clear();MODE_1(); break; //模式1
case 2: LCD_Clear();MODE_2(); break; //模式2
case 3: LCD_Clear();MODE_3(); break; //模式3
case 4: LCD_Clear();MODE_4(); break; //模式4
case 10: LCD_Clear();LCD_Main(); break; //模式选择界面
// case 20: LCD_Clear();Position_Display();break; //显示坐标函数,画圈功能(去掉该功能)
case 30: LCD_Clear();Records_Display();break; //显示记录函数
case 40: LCD_Clear();Pages_Display();break;//翻页函数
case 50: Scrolling_Display();break;//滚屏函数
// case 60: LCD_Clear();Parameter_Setting();break;//配置识别参数函数(去掉该功能)
case 70: LCD_Clear();Servos_Adjust();break;//舵机校准界面
}
}
}
-------------------------------------------------------------------------
-----------------------control.py---------------------------------------
void MODE_1(void)
{
/*
单片机——摄像头协议:
模式:01静止图片 02慢速视频 03快速视频
颜色: 00无颜色要求 01红色 02绿色 03蓝色 04黄色 05紫红
06青色 07棕色 08深绿 09深蓝 0a褐色 0b紫色 0c深青
形状:00无形状要求 01三角形 02正方形 03五边形 04六边形 05平行四边形
06三角星 07四角星 08五角星 09六角星 0a八角星
0b黑桃 0c红桃 0d方块 0e梅花 0f圆形
背景:00无 01白色 02黑色
*/
// 单片机——摄像头协议数组: 帧头,命令,模式,颜色,形状,背景,帧尾
u8 command_to_camera_start_1[7]={0xAA,0x01,0x01,0x00,0x00,0x00,0x55};//向摄像头发送的开始指令
u8 command_to_camera_stop_1 [7]={0xAA,0x00,0x01,0x00,0x00,0x00,0x55};//向摄像头发送的停止指令
// //将设置的参数写入协议数组:背景——颜色——形状
// command_to_camera_start_1[5] = setting_parameter/100;//背景
// command_to_camera_start_1[3] = (setting_parameter/10)%10;//颜色
// command_to_camera_start_1[4] = setting_parameter%10;//形状
//LCD显示文字
LCD_ShowChinese(0,0,"静态图片",RED,WHITE,32,0);
LCD_ShowChinese(0,40,"计时:",RED,WHITE,32,0);
LCD_ShowString(96,40," S",RED,WHITE,32,0);
LCD_ShowChinese(0,80,"时间:",RED,WHITE,32,0);
USART2_Send_Message(command_to_camera_start_1,7);//向摄像头发送开始识别指令
delay_s(2); //延时使摄像头初始化
USART4_Send_Message((u8*)"FJD01",6);//向电视板发送 播放指令
MODE1.timer_flag = 1; //计时开启
while(1)
{
RTC_Get();//读取RTC时钟
sprintf((char*)time_buf,"%02d:%02d:%02d",rhour,rmin,rsec);//将时间放入要在LCD屏上显示的字符串
LCD_ShowString(96,80,time_buf,RED,WHITE,32,0); //显示当前时间
LCD_ShowIntNum(96,40,MODE1.count,2,RED,WHITE,32);//显示计时时间
if(KEYPAD5x4_Read() == KEYPAD_F1)//再按F1,退回到主界面
{
MEMU = 10;
MODE1.count = 0; //定时器计时时间清0
MODE1.timer_flag = 0; //定时器计时停止
//以下两个变量为防止视频卡死,退出时清0
camera_timer_flag =0;//暂停定时标志位清0
pause_count = 0; //暂停定时计数清0,这个计时只有模式2,模式3有
bsp_Coordinate_instructions((float)(0),(float)(-19.5));//舵机初始化——复位到指定位置
USART4_Send_Message((u8*)"FJDSTOP",8);//向电视板发送 停止播放指令
delay_ms(50);
USART2_Send_Message(command_to_camera_stop_1,7);//通知摄像头停止识别
return;//##检测到按键KEYPAD5x4_Read() == KEYPAD_F1,停止视频,如何跳出函数
}
//在这进行串口接收完成等待
if(USART2_RX_STA) //接收到摄像头板发来的报文,进入坐标画圈模式,定时关闭,
{
USART2_RX_STA = 0;
Usart2_process();//分析报文数据
Usart2_ResetRXbuffer();
}
}
}
------------------------------------------------------------------------
关于裸机调度的时间片
优点:针对不同的模块,调用时间间隔不同,合理利用系统资源。
视频教材:https://cloud.189.cn/t/2uIBrya2MnIj(访问码:2jic)
main.c
typedef struct
{
uint8_t run; // 调度标志,1:调度,0:挂起
uint16_t timCount; // 时间片计数值
uint16_t timRload; // 时间片重载值
void (*pTaskFuncCb)(void); // 函数指针变量,用来保存业务功能模块函数地址
} TaskComps_t;
static TaskComps_t g_taskComps[] =
{
{0, 5, 5, HmiTask},
{0, 10, 10, WifiNetworkTask},
{0, 100, 100, SensorTask},
// {0, 1000, 1000, BatteryDrvTest},
{0, 1000, 1000, BatteryTask},
/* 添加业务功能模块 */
};
#define TASK_NUM_MAX (sizeof(g_taskComps) / sizeof(g_taskComps[0]))
static void TaskHandler(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps[i].run) // 判断时间片标志
{
g_taskComps[i].run = 0; // 标志清零
g_taskComps[i].pTaskFuncCb(); // 执行调度业务功能模块
}
}
}
/**
***********************************************************
* @brief 在定时器中断服务函数中被间接调用,设置时间片标记,
需要定时器1ms产生1次中断
* @param
* @return
***********************************************************
*/
static void TaskScheduleCb(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps[i].timCount)
{
g_taskComps[i].timCount--;
if (g_taskComps[i].timCount == 0)
{
g_taskComps[i].run = 1;
g_taskComps[i].timCount = g_taskComps[i].timRload;
}
}
}
}
static void DrvInit(void)
{
DelayInit();
LedDrvInit();
KeyDrvInit();
RtcDrvInit();
SystickInit();
WifiModuleDrvInit();
LcdDrvInit();
TempHumiDrvInit();
Pm25DrvInit();
BatteryDrvInit();
}
static void AppInit(void)
{
TaskScheduleCbReg(TaskScheduleCb);
}
int main(void)
{
DrvInit();
AppInit();
DelayNms(1000);
HmiTest();
// RtcTime_t rtcTime = {2024, 4, 15, 16, 25, 30};
// SetRtcTime(&rtcTime);
while (1)
{
TaskHandler();//
}
}
systick.c
#include <stdint.h>
#include <stdlib.h>
#include "gd32f30x.h"
static volatile uint64_t g_sysRunTime = 0;
static void (*g_pTaskScheduleFunc)(void); // 函数指针变量,保存任务调度的函数地址
/**
***********************************************************
* @brief 注册任务调度回调函数
* @param pFunc, 传入回调函数地址
* @return
***********************************************************
*/
void TaskScheduleCbReg(void (*pFunc)(void))
{
g_pTaskScheduleFunc = pFunc;
}
/**
***********************************************************
* @brief systick初始化
* @param
* @return
***********************************************************
*/
void SystickInit(void)
{
/*1ms 产生一次定时中断*/
if (SysTick_Config(rcu_clock_freq_get(CK_AHB) / 1000))
{
while (1);
}
}
/**
***********************************************************
* @brief 定时中断服务函数,1ms产生一次中断
* @param
* @return
***********************************************************
*/
void SysTick_Handler(void)
{
g_sysRunTime++;
if (g_pTaskScheduleFunc == NULL)
{
return;
}
g_pTaskScheduleFunc();
}
/**
***********************************************************
* @brief 获取系统运行时间
* @param
* @return 以1ms为单位
***********************************************************
*/
uint64_t GetSysRunTime(void)
{
return g_sysRunTime;
}
4725

被折叠的 条评论
为什么被折叠?



