Untitled

 avatar
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