Untitled
unknown
plain_text
5 months ago
6.5 kB
3
Indexable
#include <Arduino.h> #include <Energia.h> #include "i2c.h" #include "ssd1306.h" // This program is designed for a microcontroller (e.g., MSP430) running Energia or similar Arduino-compatible frameworks. // It integrates various peripherals and functionalities to demonstrate: // - Port initialization for inputs/outputs. // - Setting up a stable 25 MHz SMCLK clock using the DCO and external oscillators. // - Configuring a Timer_A PWM output to control the duty cycle based on ADC readings. // - Setting up an ADC to read analog values from a potentiometer (connected to P7.0, ADC12INCH_12). // - Using I2C to communicate with an SSD1306 OLED display for real-time visualization of ADC readings, PWM duty cycle, signal frequency, and voltage. // - Interrupt handling for the ADC to capture analog data. // The main loop adjusts the PWM output and calculates/display values dynamically based on ADC input. It also ensures periodic updates to the OLED screen. volatile char adc_flag = 0; volatile int adc_res; // Interrupt flag // Function to initialize GPIO ports for input/output configuration void init_ports() { // Configure P1.1 and P2.1 as input with pull-up resistors pinMode(P1_1, INPUT_PULLUP); digitalWrite(P1_1, HIGH); pinMode(P2_1, INPUT_PULLUP); digitalWrite(P2_1, HIGH); // Configure P4.7 and P1.0 as output pinMode(P4_7, OUTPUT); pinMode(P1_0, OUTPUT); } // Function to configure SMCLK to 25 MHz using DCO and external oscillator void init_SMCLK_25MHz() { WDTCTL = WDTPW | WDTHOLD; // Stop the watchdog timer P5SEL |= BIT2 + BIT3; // Select XT2 for SMCLK (Pins 5.2 and 5.3) P5SEL |= BIT4 + BIT5; __bis_SR_register(SCG0); // Disable FLL control loop UCSCTL0 = 0x0000; // Set lowest possible DCOx and MODx UCSCTL1 = DCORSEL_7; // Select DCO range (DCORSEL_7 for max range) UCSCTL2 = FLLD_0 + 610; // Configure multiplier for ~25 MHz DCO __bic_SR_register(SCG0); // Enable FLL control loop // Wait for oscillator stabilization do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear fault flags SFRIFG1 &= ~OFIFG; // Clear oscillator fault flags } while (SFRIFG1 & OFIFG); UCSCTL3 = SELREF__REFOCLK; // Set FLL reference to REFO UCSCTL4 = SELA__XT1CLK | SELS__DCOCLK | SELM__DCOCLK; // Set clock sources UCSCTL5 = DIVS__1; // SMCLK divider: no division } // Function to configure Timer_A for PWM generation void init_pwm() { TA2CTL |= ID_0 | TASSEL_2 | MC_3; // SMCLK source, up/down mode TA2CCTL1 |= OUTMOD_2; // Output mode: set/reset TA2CCR1 = 0; // Initial duty cycle: 0% TA2CCR0 = 1023; // PWM period pinMode(P2_0, OUTPUT); // Configure P2.0 for PWM output P2DIR |= BIT4; P2SEL |= BIT4; // Select alternate function for PWM } // Function to initialize the ADC12 module for analog-to-digital conversion void init_adc12() { ADC12CTL0 &= ~(ADC12ENC | ADC12SC); // Disable ADC before configuration ADC12CTL0 = ADC12ON | ADC12SHT0_3; // Enable ADC and configure sample time ADC12CTL1 = ADC12SHP; // Use sampling timer ADC12CTL2 = ADC12RES_1; // 10-bit resolution ADC12MCTL0 = ADC12INCH_12; // Select channel 12 (P7.0) ADC12IE |= ADC12IE0; // Enable interrupt for ADC12MEM0 ADC12CTL0 |= ADC12ENC | ADC12SC; // Enable ADC and start sampling P7SEL |= BIT0; // Enable analog input on P7.0 P7DIR &= ~BIT0; // Set P7.0 as input } // Function to get an ADC sample (blocking until conversion completes) uint16_t getSample() { while (ADC12CTL1 & ADC12BUSY) {} // Wait until ADC is not busy return ADC12MEM0; // Return ADC conversion result } // Custom function to print float values on the SSD1306 display void printFloat(int x, int y, float value, int decimal_places) { char buffer[20]; dtostrf(value, 1, decimal_places, buffer); // Convert float to string ssd1306_printText(x, y, buffer); // Display the string } int main() { init_ports(); // Initialize GPIO ports WDTCTL = WDTPW | WDTHOLD; // Stop the watchdog timer init_SMCLK_25MHz(); // Configure SMCLK init_pwm(); // Initialize Timer_A for PWM init_adc12(); // Configure ADC12 module i2c_init(); // Initialize I2C for OLED ssd1306_init(); // Initialize SSD1306 OLED display reset_diplay(); // Reset OLED display ssd1306_printText(0, 0, "Motoren starter/0"); ssd1306_clearDisplay(); // Clear OLED display uint32_t duty_cycle = 0; uint16_t period = 0; uint32_t width = 0; float frequency = 0; float voltage = 0; unsigned int adcresult; __enable_interrupt(); // Enable global interrupts while (1) { if (TA2CTL & TAIFG) { adcresult = getSample(); // Read ADC value TA2CCR1 = adcresult; // Update PWM duty cycle width = TA2CCR1 * 100; // Calculate pulse width period = TA2CCR0 + 1; // Calculate period frequency = 20000.0f / (2 * period); // Calculate frequency duty_cycle = width / period; // Calculate duty cycle voltage = (float)TA2CCR1 * 3.3f / 1024.0f; // Calculate input voltage } // Update OLED display ssd1306_printText(0, 0, "TA2CCR1:"); ssd1306_printUI32(70, 0, TA2CCR1, 0); ssd1306_printText(0, 2, "Duty Cycle:"); ssd1306_printUI32(70, 2, duty_cycle, 0); ssd1306_printText(0, 4, "Frequency:"); printFloat(70, 4, frequency, 2); ssd1306_printText(0, 6, "Voltage:"); printFloat(70, 6, voltage, 2); ADC12CTL0 |= ADC12ENC | ADC12SC; // Trigger a new ADC conversion if (adc_flag == 1) { adcresult = adc_res; // Interrupt adc_flag = 0; // Interrupt } __delay_cycles(40000); // Delay for ~40ms } } // ADC12 interrupt service routine #pragma vector=ADC12_VECTOR __interrupt void ADC12_ISR(void) { ADC12CTL0 &= ~ADC12ENC; // Disable ADC ADC12IV &= ~ADC12IFG0; // clear interrupt bit adc_res = ADC12MEM0; // Save ADC result adc_flag = 1; // Set flag for main loop ADC12CTL0 |= ADC12ENC; // Re-enable ADC }
Editor is loading...
Leave a Comment