Lissajous-Figuren mit 12 * 12 LEDs         


Elektronik-Labor  Projekte  CH32V

FQua

Michael  hat mir netterweise die Ansteuerung für sein 12*12-Display in eine h-Datei für das MouunRiver Studio übertragen, damit ich leichter damit arbeiten kann. Ich hatte dann die Idee, rotierende Lissajous-Figuren zu erzeugen. Zunächst werden zwei Sinus-Schwingungen mit 90 Grad Phasenverschiebung in x-und y-Richtung aufgetragen. Dabei entsteht ein Kreis. Ich hatte zuerst das Problem, dass durch die Rundung der Sinuswerte an den Seiten deutliche Abflachungen des Sinus entstanden. Das konnte aber durch leichte Anpassungen in der Umrechnung entschärft werden.

Nach jedem Durchlauf durch die ganze Sinustabelle fragt das Programm das rechte Poti ab und ändert bei einer Abweichung von der Mittelstellung die Phase des x-Kanals. Dadurch rotiert die Figur links- oder rechtsherum mit einstellbarer Geschwindigkeit. Dabei erscheint die Bahn noch deutlich glatter.



https://www.youtube.com/shorts/xciKOehiQhw

Interessant ist, dass dabei Helligkeitsverläufe entstehen. Jede LED wird nur für 50 µs eingeschaltet und kann daher im Laufe eines Durchgangs mehr oder weniger häufig beteiligt sein, was mehr oder weniger Helligkeit dieses Punkts ergibt.

Vor allem bei ganz langsamer Rotation ist das Bild sehr beruhigend. Wenn demnächst mal wieder mein kleiner Enkel  zu Besuch kommt, will ich mal probieren, ob das als Einschlafhilfe taugt. Insgesamt ist die Helligkeit gering, weil zu jeder Zeit nur eine von 144 LEDs leuchtet. Das und die gelbe Farbe der LEDs passen gut zur Abendstimmung.

#include "debug.h"
#include "header.h"

const uint8_t sin_table[256] =
{128,  131,  134,  137,  140,  143,  146,  149,  152,  156,  159,  162,  165,  168,  171,  173,
 176,  179,  182,  185,  188,  190,  193,  196,  199,  201,  204,  206,  209,  211,  213,  216,
 218,  220,  222,  224,  226,  228,  230,  232,  234,  235,  237,  239,  240,  242,  243,  244,
 246,  247,  248,  249,  250,  251,  251,  252,  253,  253,  254,  254,  255,  255,  255,  255,
 255,  255,  255,  255,  255,  254,  254,  253,  253,  252,  251,  251,  250,  249,  248,  247,
 246,  244,  243,  242,  240,  239,  237,  235,  234,  232,  230,  228,  226,  224,  222,  220,
 218,  216,  213,  211,  209,  206,  204,  201,  199,  196,  193,  191,  188,  185,  182,  179,
 176,  174,  171,  168,  165,  162,  159,  156,  152,  149,  146,  143,  140,  137,  134,  131,
 128,  124,  121,  118,  115,  112,  109,  106,  103,  100,  96,  93,  90,  87,  84,  82,  79,  
 76,  73,  70,  67,  65,  62,  59,  57,  54,  51,  49,  46,  44,  42,  39,  37,  35,  33,  31,
 29,  27,  25,  23,  21,  20,  18,  16,  15,  13,  12,  11,  9,  8,  7,  6,  5,  4,  4,  3,  2,
 2,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  2,  2,  3,  4,  4,  5,  6,  7,  8,  9,
 11,  12,  13,  15,  16,  18,  20,  21,  23,  25,  27,  29,  31,  33,  35,  37,  39,  42,  44,  
 46,  49,  51,  54,  56,  59,  62,  64,  67,  70,  73,  76,  79,  81,  84,  87,  90,  93,  96,
 99,  103,  106,  109,  112,  115,  118,  121,  124, };


void ADC_Config(void) {
    ADC_InitTypeDef ADC_InitStructure = {0};
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA , ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;      
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_Cmd(ADC1, ENABLE);
   
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

u16 Get_ADC(u8 ch){
    u16 val;
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_241Cycles);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    val = ADC_GetConversionValue(ADC1);
    return val;
}


void INIT_PROGRAM()
{ Delay_Init();
  ADC_Config();
  RCC->APB2PCENR |=  0b00110000;                              // enable GPIOC and GPIOD Ports
  GPIOC->CFGLR   &= ~0xFFFFFFFF; GPIOC->BCR |=  0x11111111;   // preset GPIOC Pins Low
  GPIOD->CFGLR   &= ~0x0FFFFF00; GPIOD->BCR |=  0x01111100;   // preset GPIOD Pins Low
}

int main(void)
{ INIT_PROGRAM();

  char x,y;
  char m=0,dm=1;
  char delay_time = 1;
  u16 ad;
  unsigned char tx,ty;
  tx=0; ty=64;
  while(1)
  {
    for(int n= 0;n<256;n++){
      x = (sin_table[tx]+20) /25;
      y = (sin_table[ty]+20) /25;
      draw_pixel( y, x); Delay_Us(50); clear_pixel( y, x);   
      tx++; ty++;
    }  
    ad = Get_ADC(0);
    tx=tx + (ad>>6) -8;
  }
}

Hier noch doch die header.h-Datei. Wichtig war außerdem noch, dass in system_ch32v00x.c der RC-Oszillator eingestellt wird (#define SYSCLK_FREQ_48MHZ_HSI). Nur so wird der Port A für die ADC-Eingänge freigehalten. .

char const high_pin[12][12] = { { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                                { 7, 6, 5, 4, 3, 2, 1, 0, 2, 3, 6, 5},
                              };

char const low_pin[12][12] =  { { 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
                                { 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
                                { 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
                                { 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4},
                                { 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3},
                                { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2},
                                { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
                                { 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0},
                                { 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2},
                                { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3},
                                { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
                                { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
                              };

void draw_pixel(char y, char x)
{ int L_pin, H_pin;

  L_pin = (1<<(low_pin[y][x]));                                 // Low  pin setzen
  if( y < 7 )                      { GPIOC->BCR   |= L_pin; }
  else if( ( y == 7 ) && (x > 7) ) { GPIOC->BCR   |= L_pin; }
  else                             { GPIOD->BCR   |= L_pin; }

  H_pin = (1<<(high_pin[y][x]));                                // High pin setzen
  if( x < 8 )                      { GPIOC->BSHR  |= H_pin; }
  else                             { GPIOD->BSHR  |= H_pin; }

  L_pin = (3<<((low_pin[y][x])<<2));                            // Low  pin OUTPUT enable
  if( y < 7 )                      { GPIOC->CFGLR |= L_pin; }
  else if( ( y == 7 ) && (x > 7) ) { GPIOC->CFGLR |= L_pin; }
  else                             { GPIOD->CFGLR |= L_pin; }

  H_pin = (3<<((high_pin[y][x])<<2));                           // High pin OUTPUT enable
  if( x < 8 )                      { GPIOC->CFGLR |= H_pin; }
  else                             { GPIOD->CFGLR |= H_pin; }
}

void clear_pixel(char y, char x)
{ int L_pin, H_pin;

  H_pin = (1<<(high_pin[y][x]));                                // High pin l?schen
  if( x < 8 )                      { GPIOC->BCR   |= H_pin; }
  else                             { GPIOD->BCR   |= H_pin; }

  H_pin = (0xf<<((high_pin[y][x])<<2));                         // High pin OUTPUT disable
  if( x < 8 )                      { GPIOC->CFGLR &= ~H_pin; }
  else                             { GPIOD->CFGLR &= ~H_pin; }

  L_pin = (0xf<<((low_pin[y][x])<<2));                          // Low  pin OUTPUT disable
  if( y < 7 )                      { GPIOC->CFGLR &= ~L_pin; }
  else if( ( y == 7 ) && (x > 7) ) { GPIOC->CFGLR &= ~L_pin; }
  else                             { GPIOD->CFGLR &= ~L_pin; }
}


Michael schrieb mir dazu: Eine kleine Variation deines Programms habe ich noch probiert. Es sieht aus wie der Flügelschlag eines Schmetterlings.

      x = (sin_table[tx]+20) /50;
      y = (sin_table[ty]+20) /25;
      draw_pixel( y, x); Delay_Us(50); clear_pixel( y, x);
      x = 6+(sin_table[tx]+20) /50;
      y = (sin_table[255-ty]+20) /25;
      draw_pixel( y, x); Delay_Us(50); clear_pixel( y, x);
      tx++; ty++;


Elektronik-Labor  Projekte  CH32V