Clément Grennerat 3ef9b13ce7 Setup simulated PWM
2025-08-13 22:46:26 +02:00

219 lines
7.5 KiB
C
Raw Blame History

/*
* File: main.c
* Author: clement
*
* Created on July 14, 2025, 3:54 PM
*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <pic12f1572.h>
// Configuration bits
#pragma config FOSC = INTOSC // Oscillator Selection bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config LVP = OFF
#pragma config DEBUG = ON
#pragma config PLLEN = 0
// Pins define
#define DHT22_PIN_DIR TRISAbits.TRISA4
#define DHT22_DATA PORTAbits.RA4
#define CTRL_1 PORTAbits.RA5 // Water heating - 7x27Ohm = 6.5W
#define CTRL_2 PORTAbits.RA2 // Air heating - 10x100Ohm = 2.5W
// Clock frequency (used for __delay_xx)
#define _XTAL_FREQ 8000000
// Utils macro for waiting a pin state for DHT22_DATA, returning 1 if timed out.
#define waitDHTOrRet(up) TMR0 = 0; while(DHT22_DATA != (up)){ if(TMR0 > 240) return 1; }
uint8_t dhtBytes[5]; // 2 first bytes: humidity, 2 following: temperature, 5th: checksum
// Reads the DHT, returns 0 if error
int readDHT() {
// Empty old payload
for(uint8_t i = 0; i < 5; i++){
dhtBytes[i] = 0;
}
// Wait for an old payload eventually aborted to end (lasts about 4ms)
__delay_ms(100);
// Sends the start signal: low for at least 1ms, then high for 20 to 40us
LATAbits.LATA4 = 0; // LATA4?should stay at 0, but it gets back to 1 idk why.
DHT22_PIN_DIR = 0; // configure as output, then set it as 0 (= LATAbits.LATA4).
__delay_ms(20);
DHT22_PIN_DIR = 1; // configure as input, then set it as 1 (through pullup).
__delay_us(40);
// Check DHT start response
waitDHTOrRet(0); // DHT pulls low
waitDHTOrRet(1); // DHT pulls high for 80ms
__delay_us(40);
waitDHTOrRet(0); // DHT pulls low
// Read the 5 DHT payload bytes in dhtBytes
for (uint8_t n = 0; n < 5; n++) {
for (int8_t i = 7; i >= 0; i--) {
waitDHTOrRet(1); // Wait for up
waitDHTOrRet(0); // Wait for low. Waited time is TMR0.
if (TMR0 > 50) { // Low: 26-28us High: 70us
dhtBytes[n] |= 1 << i;
}
}
}
return 0;
}
// Fetches humidity & temp from DHT, returns 0 if error
int fetchClimate(int8_t* humidity, int8_t* temperature) {
if(readDHT()) return 1;
uint8_t checksum = dhtBytes[0] + dhtBytes[1] + dhtBytes[2] + dhtBytes[3];
if (dhtBytes[4] != checksum) {
return 1; // Checksum error
}
uint16_t hum = (((uint16_t) (dhtBytes[0])) << 8) | ((uint16_t) dhtBytes[1]);
*humidity = (int8_t) (hum / 10);
uint16_t temp = (((uint16_t) (dhtBytes[2])) << 8) | ((uint16_t) dhtBytes[3]);
int8_t tempRound = (temp % 10) >= 5 ? 1 : 0;
if (temp & 0x8000) { // If high bit is 1, temperature is negative.
*temperature = - (int8_t) ((temp & 0x7FFF) / 10) - tempRound;
}else {
*temperature = (int8_t) (temp / 10) + tempRound;
}
return 0;
}
#define __delay_s(s) {uint8_t __delay_s_i = (s); while(__delay_s_i > 0){ __delay_s_i--; __delay_ms(1000); }}
#define __delay_ms2(ms) {uint8_t __delay_ms_i = (ms); while(__delay_ms_i > 0){ __delay_ms_i--; __delay_us(1000); }}
#define HEAT_DURATION 60 // When heating, heating for a minute
// Water heating at about 100% if 255, and 0% if 0.
void heat1(uint8_t rate) {
// For each tenth of second of HEAT_DURATION, heats in the proportion of rate.
uint8_t delay_on = (uint8_t) (rate / 2.55); // Total elapsed time is 16s
uint8_t delay_off = 101 - delay_on;
for(int i = 0; i < HEAT_DURATION; i++){
for(int j = 0; j < 10; j++){
CTRL_1 = 1;
__delay_ms2(delay_on);
CTRL_1 = 0;
__delay_ms2(delay_off);
}
}
}
// Global heating at about 100% if 255, and 0% if 0.
void heat2(uint8_t rate) {
// For each tenth of second of HEAT_DURATION, heats in the proportion of rate.
uint8_t delay_on = (uint8_t) (rate / 2.55); // Total elapsed time is 16s
uint8_t delay_off = 101 - delay_on;
for(int i = 0; i < HEAT_DURATION; i++){
for(int j = 0; j < 10; j++){
CTRL_2 = 1;
__delay_ms2(delay_on);
CTRL_2 = 0;
__delay_ms2(delay_off);
}
}
}
uint8_t hist_step_count = 0;
uint8_t hist_count = 0;
int8_t temp_hist[72] __at(0xA0);
int8_t hum_hist[72] __at(0x120);
void main() {
// 8MHz internal clock
OSCCON = 0b01110000;
// Ping config
TRISA = 0b11011011; // Declare RA2 and RA5 as output (bit = 0)
ANSELA = 0b00000011; // Declare used pins as digital I/O (bit = 0)
WPUA = 0b00010000; // Active la r<>sistance de pull-up sur RA4
LATAbits.LATA4 = 0; // Declare RA4 output value as 0 (only effective when DHT22_PIN_DIR = 0)
CTRL_1 = 0;
CTRL_2 = 0;
//APFCONbits.T1GSEL = 1; // Prevent T1G function to be assigned to RA4.
// Timer 0 config
OPTION_REGbits.PSA = 0; // Enable prescaler
OPTION_REGbits.PS = 0b000; // 1/2 prescaler
OPTION_REGbits.TMR0CS = 0; // Use internal clock
OPTION_REGbits.TMR0SE = 0; // Increment on rising edge
// Not using PWM as it is not working.
// PWM config PWM1 on RA5 and PWM3 on RA2
PWM3CLKCON = 0b01110000; // - Divide source clock by 128 -> 62500Hz - - FOSC clock source
PWM3PRH = 0xff; // Count to 65535 -> 1Hz full loop
PWM3PRL = 0xff;
PWM3PHH = 0; // No phase count
PWM3PHL = 0;
PWM3OFH = 0; // No offset
PWM3OFL = 0;
PWM3DCH = 0; // Comparator set to 0 -> always off
PWM3DCL = 0;
//PWM3CON = 0b11000000; // Module enable - Output enable - Output state 0 (off) - Output active state is high - Standard PWM mode
APFCONbits.P1SEL = 1; // PWM1 on RA5
PWM1CLKCON = 0b01110000; // - Divide source clock by 128 -> 62500Hz - - FOSC clock source
PWM1PRH = 0xff; // Count to 65535 -> 1Hz full loop
PWM1PRL = 0xff;
PWM1PHH = 0; // No phase count
PWM1PHL = 0;
PWM1OFH = 0; // No offset
PWM1OFL = 0;
PWM1DCH = 0; // Comparator set to 0 -> always off
PWM1DCL = 0;
//PWM1CON = 0b11000000; // Module enable - Output enable - Output state 0 (off) - Output active state is high - Standard PWM mode
// Target (except from nov. to feb.: 15<31>):
// temp = 24 to 28<32>
// hum = 60 to 80%
int8_t hum_target = ((int8_t) 80);
int8_t temp_target = ((int8_t) 40);
while (1) {
int8_t hum = 0;
int8_t temp = 0;
int is_error = fetchClimate(&hum, &temp);
__delay_ms(100);
hist_step_count++;
if(hist_step_count == 10) {
hist_step_count = 0;
temp_hist[hist_count] = temp;
hum_hist[hist_count] = hum;
hist_count++;
}
if(is_error){
LATAbits.LATA4 = 0;
__delay_ms(1000);
}else{
if(hum < hum_target){
heat1(128); // 50% Power
}else if(temp < temp_target){
heat2(128);
}else {
__delay_s(HEAT_DURATION);
}
}
//PWM3DCH = 128; // 50% power
//PWM1DCH = 128; // 50% power
}
}