326 lines
9.5 KiB
C
326 lines
9.5 KiB
C
/*
|
|
* main.c
|
|
*
|
|
* Created on: 2023年7月4日
|
|
* Author: User
|
|
*/
|
|
|
|
#include "main.h"
|
|
|
|
#include <STDIO.H>
|
|
#include <STDLIB.H>
|
|
#include <STRING.H>
|
|
|
|
#include "ADC.h"
|
|
#include "GPIO.h"
|
|
#include "NTC100K.h"
|
|
#include "UART.h"
|
|
#include "delay.h"
|
|
#include "ring.h"
|
|
#include "timer.h"
|
|
#include "ws2812.h"
|
|
|
|
#define NTC_CHANNEL ADC_CH1
|
|
#define ADC_START_NTC ADC_CONTR = (ADC_CONTR & 0xf0) | ADC_START | NTC_CHANNEL;
|
|
|
|
#define PWM_ARR 199 // PWM频率设置 20M / (199 + 1) = 100KHz => 10us
|
|
|
|
static u8 tick; // 每秒计时的标志 1s
|
|
static u8 update; // 更新PWM的标志 10ms
|
|
static u32 sysTime; // 系统计时时钟 1ms
|
|
static u16 curTemp; // 当前温度
|
|
static u16 curPwm; // 当前PWM百分比
|
|
|
|
// NTC的ADC数据缓冲区
|
|
static u16 xdata ntcAdcBuf[ADC_BUF_LENGTH];
|
|
|
|
// static u32 led[7] = {WS2812B_RED, WS2812B_ORANGE, WS2812B_YELLOW, WS2812B_GREEN,
|
|
// WS2812B_CYAN, WS2812B_BLUE, WS2812B_PURPLE};
|
|
// static u32 led[7] = {WS2812B_CYAN, WS2812B_CYAN, WS2812B_CYAN, WS2812B_CYAN, WS2812B_CYAN, WS2812B_CYAN,
|
|
// WS2812B_CYAN}; static u8 *p_led = led, v_led = 0, b_led = 0, b_num = 0; static u8 num = 0;
|
|
|
|
/**
|
|
* 主函数
|
|
*/
|
|
void main() {
|
|
init();
|
|
|
|
while (1) core();
|
|
}
|
|
|
|
static void GPIOInit() {
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
// 准双向端口
|
|
GPIO_InitStructure.Mode = GPIO_PullUp;
|
|
GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
|
|
GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); // P30,P31,P32,P33,P35,P36,P37
|
|
GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
|
|
GPIO_Inilize(GPIO_P1, &GPIO_InitStructure); // P10,P13,P14,P15,P16,P17
|
|
GPIO_InitStructure.Pin = GPIO_Pin_4;
|
|
GPIO_Inilize(GPIO_P5, &GPIO_InitStructure); // P54
|
|
|
|
// 推挽端口
|
|
GPIO_InitStructure.Mode = GPIO_OUT_PP;
|
|
GPIO_InitStructure.Pin = GPIO_Pin_4;
|
|
GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); // P34
|
|
GPIO_InitStructure.Pin = GPIO_Pin_2;
|
|
GPIO_Inilize(GPIO_P1, &GPIO_InitStructure); // P12
|
|
|
|
// 高阻端口
|
|
GPIO_InitStructure.Mode = GPIO_HighZ;
|
|
GPIO_InitStructure.Pin = GPIO_Pin_1;
|
|
GPIO_Inilize(GPIO_P1, &GPIO_InitStructure); // P11
|
|
}
|
|
|
|
static void uartInit() {
|
|
COMx_InitDefine COMx_InitStructure; // 结构定义
|
|
|
|
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; // 8N1模式
|
|
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; // 选择波特率发生器
|
|
COMx_InitStructure.UART_BaudRate = 115200ul; // 波特率 115200
|
|
COMx_InitStructure.UART_RxEnable = TRUE; // 不需要接收
|
|
COMx_InitStructure.BaudRateDouble = DISABLE; // 波特率不加倍
|
|
COMx_InitStructure.UART_Interrupt = ENABLE; // 中断使能
|
|
COMx_InitStructure.UART_Priority = Priority_0; // 中断优先级
|
|
UART_Configuration(UART1, &COMx_InitStructure); // 初始化串口1
|
|
}
|
|
|
|
static void ADCInit() {
|
|
ADC_InitTypeDef ADC_InitStructure; // 结构定义
|
|
ADC_InitStructure.ADC_SMPduty = 31; // ADC 模拟信号采样时间控制
|
|
ADC_InitStructure.ADC_Speed = ADC_SPEED_2X1T; // ADC 工作时钟频率
|
|
ADC_InitStructure.ADC_Power = ENABLE; // ADC 电源打开
|
|
ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; // ADC 结果调整
|
|
ADC_InitStructure.ADC_Priority = Priority_0; // ADC 优先级
|
|
ADC_InitStructure.ADC_Interrupt = DISABLE; // ADC 禁用中断
|
|
ADC_InitStructure.ADC_CsSetup = 0; // ADC 通道选择时间控制 0(默认),1
|
|
ADC_InitStructure.ADC_CsHold = 1; // ADC 通道选择保持时间控制 0,1(默认),2,3
|
|
ADC_Inilize(&ADC_InitStructure); // 初始化ADC
|
|
|
|
// ADC_CONTR = ADC_CONTR | ADC_EPWMT; //使能PWM同步触发
|
|
ADC_START_NTC; // 启动ADC转换
|
|
}
|
|
|
|
static void PWMInit() {
|
|
EAXSFR();
|
|
|
|
// // 配置PWM4 用于控制WS2812
|
|
// PWM4_USE_P34P33();
|
|
// PWMA_CC4E_Disable(); // 关闭输入捕获/比较输出
|
|
// PWMA_CC4NE_Disable(); // 关闭比较输出
|
|
// PWMA_OC4_RelosdDisable(); // 禁止 OC4PE 输出比较的预装载功能
|
|
// PWMA_CC4S_Direction(CCAS_OUTPUT); // CCnS仅在通道关闭时才是可写的
|
|
// PWMA_OC4ModeSet(CCMRn_PWM_MODE1); // 设置输出比较模式
|
|
// PWMA_CC4E_Enable(); // 开启比较输出
|
|
// PWM4P_OUT_EN(); // 开启输出通道
|
|
// PWMA_Duty4(0);
|
|
|
|
// 配置PWM2
|
|
PWMA_CC2E_Disable(); // 关闭输入捕获/比较输出
|
|
PWMA_CC2NE_Disable(); // 关闭比较输出
|
|
PWMA_OC2_ReloadEnable(); // 允许 OC2PE 输出比较的预装载功能
|
|
PWMA_CC2S_Direction(CCAS_OUTPUT); // CCnS仅在通道关闭时才是可写的
|
|
PWMA_OC2ModeSet(CCMRn_PWM_MODE1); // 设置输出比较模式
|
|
PWMA_CC2E_Enable(); // 开启比较输出
|
|
PWM2P_OUT_EN(); // 开启输出通道
|
|
PWMA_Duty2(0);
|
|
|
|
// 配置PWMA
|
|
PWMA_CCPCAPreloaded(DISABLE);
|
|
PWMA_AutoReload(199); // 周期设置 100KHz = 10us
|
|
PWMA_BrakeOutputEnable(); // 主输出使能
|
|
PWMA_CEN_Enable(); // 使能计数器
|
|
|
|
EAXRAM();
|
|
}
|
|
|
|
static void timerInit() {
|
|
u16 timePreVal = 65536UL - 1000 * (MAIN_Fosc / 1000000UL); // 1ms
|
|
|
|
TIM_InitTypeDef TIM_InitStructure; // 结构定义
|
|
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReloadNoMask; // 16位自动重载,不可屏蔽
|
|
TIM_InitStructure.TIM_Interrupt = ENABLE; // 允许中断
|
|
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; // 内部时钟1T
|
|
TIM_InitStructure.TIM_ClkOut = DISABLE; // 不输出高速脉冲
|
|
TIM_InitStructure.TIM_Value = timePreVal; // 设置初值
|
|
TIM_InitStructure.TIM_Run = ENABLE; // 启动定时器
|
|
Timer_Inilize(Timer0, &TIM_InitStructure); // 初始化Timer0
|
|
}
|
|
|
|
static u16 getNTC();
|
|
static u16 getTemp();
|
|
static u8 calcPWM(u16 temp);
|
|
static void updataPWM(u8 pwmPercent);
|
|
|
|
void init() {
|
|
GPIOInit();
|
|
uartInit();
|
|
timerInit();
|
|
ADCInit();
|
|
PWMInit();
|
|
|
|
// 初始化缓存队列
|
|
InitRing(&adcRing);
|
|
|
|
Delay50ms();
|
|
|
|
EADC = 1; // 启动ADC中断
|
|
EA = 1; // 启动全局中断
|
|
}
|
|
|
|
void core() {
|
|
curTemp = getTemp();
|
|
curPwm = calcPWM(curTemp);
|
|
|
|
if (update) { // 每10ms执行一次PWM更新
|
|
updataPWM(curPwm);
|
|
}
|
|
|
|
if (tick) { // 每一秒执行一次状态报告
|
|
char string[30] = {0};
|
|
sprintf(string, "temp: %3dC, pwm: %3d%%\r\n", curTemp, curPwm);
|
|
PrintString1(string);
|
|
tick = FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 1024 / (4700 + R) = ADC / R
|
|
* => R = (4700 * ADC) / (1024 - ADC)
|
|
*
|
|
* NTC100K 单位是 10 Ω
|
|
* return (R / 10)
|
|
*/
|
|
static u16 getNTC() {
|
|
if (adcRing.full) {
|
|
u8 i;
|
|
u16 max = 0, min = 1024;
|
|
u16 sum = 0, raw = 0, avg = 0, res = 0;
|
|
EA = 0;
|
|
memcpy(ntcAdcBuf, adcRing.buf, sizeof(ntcAdcBuf));
|
|
EA = 1;
|
|
for (i = 0; i < ADC_BUF_LENGTH; i++) {
|
|
raw = ntcAdcBuf[i];
|
|
sum += raw;
|
|
if (raw > max) max = raw;
|
|
if (raw < min) min = raw;
|
|
}
|
|
sum = sum - min - max;
|
|
avg = sum / (ADC_BUF_LENGTH - 2);
|
|
res = (47 * avg) / (1024 - avg);
|
|
if (res > 6553)
|
|
return 0xFFFF;
|
|
else
|
|
return res * 10;
|
|
} else {
|
|
return 0xFFFF;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取当前温度
|
|
* 阻值表的索引值即是温度值
|
|
*/
|
|
static u16 getTemp() {
|
|
u16 i, raw = getNTC();
|
|
for (i = 0; i < sizeof(NTC100K); i++) {
|
|
if (raw >= NTC100K[i]) break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* 根据输入的温度计算PWM百分比
|
|
* TODO 串口输入调整对应参数
|
|
*
|
|
* 最小启动风扇百分比 默认20%
|
|
* 风扇启动温度 默认35C
|
|
* 风扇最大温度 默认65C
|
|
*/
|
|
static u8 calcPWM(u16 temp) {
|
|
if (temp < 35) {
|
|
return 0;
|
|
} else if (temp > 65) {
|
|
return 100;
|
|
} else {
|
|
return 20 + (temp - 35) * (100 - 20) / (65 - 35);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新PWM占空比, 输入百分比
|
|
*/
|
|
static void updataPWM(u8 pwmPercent) {
|
|
u16 duty;
|
|
if (pwmPercent > 100) pwmPercent = 100;
|
|
duty = pwmPercent * (PWM_ARR + 1) / 100;
|
|
EAXSFR();
|
|
PWMA_Duty2(duty);
|
|
EAXRAM();
|
|
}
|
|
|
|
/**
|
|
* Timer0中断
|
|
*/
|
|
void timer0_ISR(void) interrupt TIMER0_VECTOR {
|
|
ADC_START_NTC; // 每1ms启动一次ADC转换
|
|
sysTime++;
|
|
if (sysTime % 10 == 0) {
|
|
update = TRUE;
|
|
if (sysTime % 1000 == 0) {
|
|
tick = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ADC中断
|
|
*/
|
|
void ADC_ISR() interrupt ADC_VECTOR {
|
|
ADC_CONTR &= ~ADC_FLAG;
|
|
SaveRing(&adcRing, ((u16)ADC_RES << 8) | ADC_RESL);
|
|
}
|
|
|
|
/**
|
|
* PWM中断
|
|
*/
|
|
void PWMA_ISR() interrupt PWMA_VECTOR {
|
|
// if (PWMA_SR1 & UIF1) {
|
|
// PWMA_SR1 &= ~UIF1;
|
|
// }
|
|
// if (PWMA_SR1 & CC4IF) {
|
|
// // if (num++ == 72) {
|
|
// // num--;
|
|
// // EAXSFR();
|
|
// // PWMA_CCR4 = 0;
|
|
// // EAXRAM();
|
|
// // PWMA_SR1 &= ~CC4IF;
|
|
|
|
// // } else {
|
|
// // v_led = *p_led;
|
|
// // switch (b_num++) {
|
|
// // case 0: b_led = v_led & 0x80; break;
|
|
// // case 1: b_led = v_led & 0x40; break;
|
|
// // case 2: b_led = v_led & 0x20; break;
|
|
// // case 3: b_led = v_led & 0x10; break;
|
|
// // case 4: b_led = v_led & 0x08; break;
|
|
// // case 5: b_led = v_led & 0x04; break;
|
|
// // case 6: b_led = v_led & 0x02; break;
|
|
// // case 7: b_led = v_led & 0x01;
|
|
// // default:
|
|
// // b_num = 0;
|
|
// // p_led++;
|
|
// // break;
|
|
// // }
|
|
// // EAXSFR();
|
|
// // if (b_led)
|
|
// // PWMA_CCR4 = 16;
|
|
// // else
|
|
// // PWMA_CCR4 = 8;
|
|
// // EAXRAM();
|
|
// // PWMA_SR1 &= ~CC4IF;
|
|
// // }
|
|
// }
|
|
}
|