时间片轮询调度
uint8_t TaskCount = 0;//用于记录任务数量
typedef enum {
run,wait,stop
}TaskStatus;//任务状态
typedef struct {
uint8_t TaskRunTime;
uint8_t TaskTimer;
TaskStatus Status;
void (*FC)();
}TaskStrust;//任务信息块:注意两点1.注意Timer和runtime的数据类型为uchar,最大为255 2.时间片为2ms
TaskStrust TaskList[]={0};
void OS_Init(TIM_HandleTypeDef* htim){
HAL_TIM_Base_Start_IT(htim);
TaskCount = sizeof(TaskList)/sizeof(TaskList[1]);
if(TaskCount > MAX_TASK) while(1);
}
void OS_IT_Run(void){
uint8_t i;
for(i = 0;i < TaskCount;i++){
if(TaskList[i].Status == wait){
if(++TaskList[i].TaskTimer >= TaskList[i].TaskRunTime){
TaskList[i].TaskTimer = 0;
TaskList[i].Status = run;
}
}
}
}
//自带死循环,主函数里运行
void OS_Run(void){
uint8_t j = 0;
while(1){
if(TaskList[j].Status == run){
TaskList[j].FC();
TaskList[j].Status = wait;
}
if(++j >= TaskCount) j = 0;
}
}
频率测量
核心思路:
1/((这一次的计数值-上一次记录的计数值)x (1/时钟频率))= 时钟频率/(记录差值)
typedef struct {
uint8_t i;//记录当前是第几次。
int former;//前一次记录的计数值
int now;//现在记录的计数值
int result;//频率结果
uint8_t ElapsedTime;//定时器溢出次数
}FreqInfo;
reqInfo F1 = {0};
FreqInfo F2 = {0};
//启动频率测量
void Freq_Start(void){
HAL_TIM_Base_Start_IT(&htim3);//对应F1
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&htim8);//对应F2
HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
}
static void Freq_Measure(FreqInfo* Fx,TIM_HandleTypeDef *htim){
if(Fx->i == 0){
Fx->result = 1000000/(Fx->now - Fx->former);
__HAL_TIM_ENABLE(htim);
}
}
void Freq_Fuc(void){
Freq_Measure(&F1,&htim3);
Freq_Measure(&F2,&htim8);
}
//中断
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM3){
switch(F1.i){
case 0:
F1.former = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1) + 65535 * F1.ElapsedTime;
F1.i = 1;
break;
case 1:
F1.now = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1) + 65535 * F1.ElapsedTime;
__HAL_TIM_DISABLE(&htim3);
F1.ElapsedTime = 0;
F1.i = 0;
break;
default:break;
}
}
else if(htim->Instance == TIM8){
switch(F2.i){
case 0:
F2.former = HAL_TIM_ReadCapturedValue(&htim8,TIM_CHANNEL_1) + 65535 * F2.ElapsedTime;
F2.i = 1;
break;
case 1:
F2.now = HAL_TIM_ReadCapturedValue(&htim8,TIM_CHANNEL_1) + 65535 * F2.ElapsedTime;
__HAL_TIM_DISABLE(&htim8);
F2.ElapsedTime = 0;
F2.i = 0;
break;
default:break;
}
}
}
//在溢出中断中记录溢出次数
共享变量
#include "SharedData.h"
//初始化
static Data1 shareddata1 = {0,0};
//获取Data1指针的接口
Data1* get_shared_data(void) {
return &shareddata1;
}
按键
uint8_t KeyBit(void){
uint8_t keybit = 0x00;
//读取B1的电平状态并把他左移到bit0位
keybit |= HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin) << 0;
//同上
keybit |= HAL_GPIO_ReadPin(B2_GPIO_Port,B2_Pin) << 1;
keybit |= HAL_GPIO_ReadPin(B3_GPIO_Port,B3_Pin) << 2;
keybit |= HAL_GPIO_ReadPin(B4_GPIO_Port,B4_Pin) << 3;
return keybit;
}
void task_Key(void){
static uint8_t Trg,Cont;
unsigned char ReadData = KeyBit() ^ 0x0f; // 取反:在没有按键按下的情况下,其始终为0x00
Trg = ReadData & (ReadData ^ Cont); // 2
Cont = ReadData;
if(Trg && Cont){};
if(Trg && Cont == 0){};
}
LCD
引脚初始化为全低就行
LED
LD口 为 PD2 低电平不允许写入,高电平允许写入。
#include "LED.h"
#include "SharedData.h"
uint16_t LD_state = 0; //记录LD各位状态
uint16_t LD_state_before = 0;
void LED_init(void){
HAL_GPIO_WritePin(LD1_GPIO_Port,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_load_GPIO_Port,LD_load_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_load_GPIO_Port,LD_load_Pin,GPIO_PIN_RESET);
}
void LED_lightLD(uint8_t LDnum){
LD_state |= (LD1_Pin << LDnum); //其他位不变,需要改变的位变为1
}
void LED_closeLD(uint8_t LDnum){
LD_state &= ~(LD1_Pin << LDnum); //其他位不变,需改变的位变为0
}
void Call_ChangeLD(void(*fc)(uint8_t),uint8_t LDnum){
LDnum -= 1;
fc(LDnum);
if(LD_state_before != LD_state){
HAL_GPIO_WritePin(LD_load_GPIO_Port,LD_load_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD1_GPIO_Port,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD1_GPIO_Port,LD_state,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LD_load_GPIO_Port,LD_load_Pin,GPIO_PIN_RESET);
LD_state_before = LD_state;
}
else return;
}
void LED_Fuc(void){
if(Read_Show_index(0)) {
Call_ChangeLD(LED_closeLD,1);
Call_ChangeLD(LED_lightLD,2);
}
else {
Call_ChangeLD(LED_closeLD,2);
Call_ChangeLD(LED_lightLD,1);
}
if(Read_Show_index(1)){
Call_ChangeLD(LED_lightLD,8);
}
else Call_ChangeLD(LED_closeLD,8);
}
串口重定向与数据处理
#define BUFFER_SIZE 50
#define CMDNUM 6
void TF1(void);
void TF2(void);
void PF1(void);
void PF2(void);
void returnF1(void);
void returnF2(void);
char rx_DataBuffer[BUFFER_SIZE] = {0};
char tx_DataBuffer[BUFFER_SIZE] = {0};
char cmd[BUFFER_SIZE] = {0};
uint16_t tx_len = 0; // 当前缓冲区数据长度
uint8_t tx_busy = 0; // 发送状态标志
uint8_t rx_handle = 0; //处理接收数据标志
uint8_t rx_len = 0;
typedef struct{
uint8_t* cmd_str;
void (*fc)();
}cmdinfo;
cmdinfo cmdlist[] = {
{"TF1",TF1},
{"TF2",TF2},
{"PF1",PF1},
{"PF2",PF2},
{"F1",returnF1},
{"F2",returnF2}
};
void TheUART_start(void){
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,(uint8_t*)rx_DataBuffer,0x0f);
}
void TheUART_dma_transmit(void)
{
// 如果 DMA 还在忙,则不启动新的传输
if (tx_busy) return;
tx_busy = 1; // 标记为发送中
HAL_UART_Transmit_DMA(&huart1,(uint8_t*)tx_DataBuffer,tx_len-1);//-1为了防止傻逼烂桥杯的验证程序不通过
}
int fputc(int ch, FILE *f)
{
// 确保缓冲区不会溢出
if (tx_len < BUFFER_SIZE - 1)
{
tx_DataBuffer[tx_len++] = (uint8_t)ch;
}
// 如果遇到换行符,或者缓冲区接近满,就启动 DMA 发送
// 注意咯,如果缓冲区没满的情况下,只有检测到/n才会触发DMA的发送。所以在缓
// 冲区没满的情况下,如果你想要发送字符串"abc",printf("abc")是没用的,
// printf("abc\n")才有用哦。
if (ch == '\n' || tx_len >= BUFFER_SIZE - 1)
{
TheUART_dma_transmit();
}
return ch;
}
void TheUART_HandleRxdata(void){
if(rx_handle == 1){
uint8_t i = 0;
strcpy(cmd,rx_DataBuffer);
cmd[rx_len] = '\0';
if(!Read_Show_index(1)){
other();
rx_len = 0;
rx_handle = 0;
TheUART_start();
return;
}
for(i = 0;i < CMDNUM;i++){
if(strcmp((const char*)cmd,(const char*)cmdlist[i].cmd_str) == 0){
cmdlist[i].fc();
rx_len = 0;
rx_handle = 0;
TheUART_start();
return;
}
}
other();
rx_len = 0;
rx_handle = 0;
TheUART_start();
}
else return;
}
//命令函数
void TF1(void){
}
void TF2(void){
}
void PF1(void){
}
void PF2(void){
}
void returnF1(void){
}
void returnF2(void){
}
void other(void){
}
//中断
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 确保是目标串口
{
tx_len = 0; // 清空缓冲区
tx_busy = 0; // 标记为可用
}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
if(huart->Instance == USART1){
rx_len = Size;
rx_handle = 1;
}
}
ADC:使用定时器TRGO信号触发ADC转换
double ADC_Data = .0;
void ADCFuc_Init(ADC_HandleTypeDef *hadc){
HAL_ADCEx_Calibration_Start(hadc,ADC_SINGLE_ENDED);//校准
HAL_ADC_Start_IT(hadc);
}
char ADCFuc_ReturnResult(void){
double result = ADC_Data;
result = (result / 4095.0) * 3.3;
}
//中断-------------------------------------------------------------//
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc){
if(hadc->Instance == ADC2){
ADC_Data = HAL_ADC_GetValue(&hadc2);
}
}
at24c02
include "i2c_hal.h"
#define COMMAND_W 0xA0
#define COMMAND_R 0xA1
void at24c02_Init(void){
I2CInit();
}
/// @brief at24c02写数据
/// @param address 要写入的地址
/// @param data 要写入的数据
void at24c02_Write(uint8_t address,uint8_t data){
I2CStart();
I2CSendByte(COMMAND_W);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
/// @brief at24c02读数据
/// @param address 要读数据的地址
/// @return 读出的数据
uint8_t at24c02_Read(uint8_t address){
uint8_t data = 0;
I2CStart();
I2CSendByte(COMMAND_W);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();//不释放总线的情况下重启通信,发送读命令。
I2CSendByte(COMMAND_R);
I2CWaitAck();
data = I2CReceiveByte();
I2CSendNotAck();//通知从机不再发送数据
I2CStop();
return data;
}
韩信在干嘛?韩信在偷塔!能做到吗?哇他出了一个名刀·司命!猫雷!
挂一张梦老师保佑!
