added firmware section
This commit is contained in:
169
firmware/main.c
Normal file
169
firmware/main.c
Normal file
@@ -0,0 +1,169 @@
|
||||
#include "ch32fun.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// ==========================================
|
||||
// PIN CONFIGURATION (CH32V003J4M6 - SOP8)
|
||||
// ==========================================
|
||||
// Package Pin 1: PD6 (FLOW_PULSE_MCU) -> EXTI Input
|
||||
// Package Pin 3: PA2 (ALARM_TRIGGER) -> GPIO Output
|
||||
// Package Pin 5: PC1 (I2C_SDA) -> Bitbang or HW I2C
|
||||
// Package Pin 6: PC2 (I2C_SCL) -> Bitbang or HW I2C
|
||||
// Package Pin 7: PC4 (BUTTON_ADC) -> ADC Channel 2 Input
|
||||
// Package Pin 8: PD1 (SWIO) -> Programming & Logging
|
||||
|
||||
#define FLOW_PIN 6 // PD6 = bit 6 of GPIOD
|
||||
#define ALARM_PIN 2 // PA2 = bit 2 of GPIOA
|
||||
#define BUTTON_PIN 4 // PC4 = bit 4 of GPIOC
|
||||
|
||||
// Constants
|
||||
#define FLOW_CONVERSION_FACTOR 5.5 // L/min = Hz / 5.5 (Adjust for ZJ-S401)
|
||||
|
||||
#define ADC_UP_BTN_MAX 200 // Button 1 range: 50..200 (center ~93)
|
||||
#define ADC_UP_BTN_MIN 20
|
||||
#define ADC_DOWN_BTN_MAX 15 // Button 2 range: 0..15 (should read ~0)
|
||||
|
||||
#define DEBOUNCE_DELAY_MS 200
|
||||
|
||||
// Globals
|
||||
volatile uint32_t pulse_count = 0;
|
||||
uint32_t flow_rate_ml_min = 0; // Stored in mL/min for integer precision
|
||||
uint32_t threshold_ml_min = 2000; // Default: 2.0 L/min
|
||||
uint8_t alarm_active = 0; // Track state to prevent log spam (0 = OK, 1 = ALARM)
|
||||
|
||||
// ==========================================
|
||||
// INTERRUPT HANDLER (Flow Sensor Pulses)
|
||||
// ==========================================
|
||||
void EXTI7_0_IRQHandler(void) __attribute__((interrupt));
|
||||
void EXTI7_0_IRQHandler(void) {
|
||||
if (EXTI->INTFR & (1 << FLOW_PIN)) {
|
||||
pulse_count++;
|
||||
EXTI->INTFR = (1 << FLOW_PIN); // Clear interrupt flag
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// HARDWARE INITIALIZATION
|
||||
// ==========================================
|
||||
void Init_Hardware(void) {
|
||||
// 1. Enable Clocks for GPIOA, GPIOC, GPIOD, ADC, AFIO
|
||||
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO;
|
||||
|
||||
// 2. Configure ALARM_TRIGGER Output (PA2) - Push-Pull
|
||||
GPIOA->CFGLR &= ~(0xF << (4 * ALARM_PIN));
|
||||
GPIOA->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * ALARM_PIN);
|
||||
GPIOA->BSHR = (1 << (16 + ALARM_PIN)); // Default to ALARM STATE (Low = MOSFET OFF)
|
||||
|
||||
// 3. Configure FLOW_PULSE_MCU Input (PD6) - Pull-up
|
||||
GPIOD->CFGLR &= ~(0xF << (4 * FLOW_PIN));
|
||||
GPIOD->CFGLR |= (GPIO_CNF_IN_PUPD) << (4 * FLOW_PIN);
|
||||
GPIOD->BSHR = (1 << FLOW_PIN); // Enable pull-up
|
||||
|
||||
// Setup EXTI on PD6 (CH32V003 has single EXTICR, 2 bits per pin, Port D = 0b11)
|
||||
AFIO->EXTICR |= (0b11 << (FLOW_PIN * 2)); // PD6: Port D=0b11, bits [13:12]
|
||||
EXTI->INTENR |= (1 << FLOW_PIN); // Enable EXTI interrupt on line 6
|
||||
EXTI->FTENR |= (1 << FLOW_PIN); // Falling edge trigger
|
||||
NVIC_EnableIRQ(EXTI7_0_IRQn); // Enable interrupt in NVIC
|
||||
|
||||
// 4. Configure BUTTON_ADC Input (PC4 / AIN2) - Analog mode (no pull)
|
||||
GPIOC->CFGLR &= ~(0xF << (4 * BUTTON_PIN));
|
||||
|
||||
// Setup ADC
|
||||
ADC1->CTLR2 |= ADC_ADON; // Turn on ADC
|
||||
ADC1->RSQR3 = 2; // PC4 is ADC Channel 2 (AIN2)
|
||||
ADC1->SAMPTR2 = 7 << (3 * 2); // Max sampling time for CH2
|
||||
|
||||
ADC1->CTLR2 |= ADC_RSTCAL; // Reset & calibrate
|
||||
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||
ADC1->CTLR2 |= ADC_CAL;
|
||||
while(ADC1->CTLR2 & ADC_CAL);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// HELPER FUNCTIONS
|
||||
// ==========================================
|
||||
uint16_t Read_ADC(void) {
|
||||
ADC1->CTLR2 |= ADC_SWSTART;
|
||||
while(!(ADC1->STATR & ADC_EOC));
|
||||
return ADC1->RDATAR;
|
||||
}
|
||||
|
||||
void Update_Display(uint32_t current_flow, uint32_t threshold) {
|
||||
// TODO: Implement OLED I2C drawing here using ch32fun's I2C bitbang
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// MAIN LOOP
|
||||
// ==========================================
|
||||
int main() {
|
||||
SystemInit();
|
||||
Init_Hardware();
|
||||
|
||||
printf("\r\n==================================\r\n");
|
||||
printf(" CNC Flow Controller Initialized\r\n");
|
||||
printf("==================================\r\n");
|
||||
printf("[INFO] Active Threshold: %lu mL/min\r\n", threshold_ml_min);
|
||||
|
||||
uint32_t last_time = SysTick->CNT;
|
||||
uint32_t last_button_time = 0;
|
||||
|
||||
while(1) {
|
||||
uint32_t current_time = SysTick->CNT;
|
||||
uint32_t ticks_per_sec = DELAY_US_TIME * 1000000; // = FUNCONF_SYSTEM_CORE_CLOCK
|
||||
|
||||
// --- 1. EVALUATE FLOW EVERY 1 SECOND ---
|
||||
if ((current_time - last_time) >= ticks_per_sec) {
|
||||
last_time = current_time;
|
||||
|
||||
// Copy and reset pulse count safely
|
||||
NVIC_DisableIRQ(EXTI7_0_IRQn);
|
||||
uint32_t hz = pulse_count;
|
||||
pulse_count = 0;
|
||||
NVIC_EnableIRQ(EXTI7_0_IRQn);
|
||||
|
||||
// Calculate Flow: L/min = Hz / 5.5 => mL/min = (Hz * 10000) / 55
|
||||
flow_rate_ml_min = (hz * 10000) / 55;
|
||||
|
||||
// --- 2. FAILSAFE LOGIC & LOGGING ---
|
||||
if (flow_rate_ml_min >= threshold_ml_min) {
|
||||
// Flow OK -> Drive ALARM_PIN High (MOSFET ON, CNC OK)
|
||||
GPIOA->BSHR = (1 << ALARM_PIN);
|
||||
|
||||
if (alarm_active == 1) {
|
||||
alarm_active = 0;
|
||||
printf("[INFO] Flow restored: %lu mL/min. Alarm CLEARED.\r\n", flow_rate_ml_min);
|
||||
}
|
||||
} else {
|
||||
// Flow Low -> Drive ALARM_PIN Low (MOSFET OFF, CNC Alarm)
|
||||
GPIOA->BSHR = (1 << (16 + ALARM_PIN));
|
||||
|
||||
if (alarm_active == 0) {
|
||||
alarm_active = 1;
|
||||
printf("[WARN] Low flow detected: %lu mL/min (Thr: %lu). Alarm TRIGGERED!\r\n", flow_rate_ml_min, threshold_ml_min);
|
||||
}
|
||||
}
|
||||
|
||||
Update_Display(flow_rate_ml_min, threshold_ml_min);
|
||||
}
|
||||
|
||||
// --- 3. BUTTON HANDLING (ADC Resistor Ladder) ---
|
||||
// Thresholds match actual voltages: no-press ~1023, BTN1 ~93, BTN2 ~0.
|
||||
uint16_t adc_val = Read_ADC();
|
||||
|
||||
if ((current_time - last_button_time) > (DEBOUNCE_DELAY_MS * DELAY_US_TIME * 1000)) {
|
||||
if (adc_val >= ADC_UP_BTN_MIN && adc_val <= ADC_UP_BTN_MAX) {
|
||||
// Button 1: voltage divider 10k+1k -> ~0.30V -> ADC ~93
|
||||
threshold_ml_min += 100;
|
||||
last_button_time = current_time;
|
||||
printf("[SET] Threshold increased to: %lu mL/min\r\n", threshold_ml_min);
|
||||
Update_Display(flow_rate_ml_min, threshold_ml_min);
|
||||
}
|
||||
else if (adc_val <= ADC_DOWN_BTN_MAX) {
|
||||
// Button 2: direct to GND -> ~0V -> ADC ~0
|
||||
if (threshold_ml_min >= 100) threshold_ml_min -= 100;
|
||||
last_button_time = current_time;
|
||||
printf("[SET] Threshold decreased to: %lu mL/min\r\n", threshold_ml_min);
|
||||
Update_Display(flow_rate_ml_min, threshold_ml_min);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user