/* -------------------------------------------------------- rechteck_j4m6.c Einfacher Rechteckgenerator mit 4 mittels einem Taster umschaltbaren Frequenzbereich MCU : CH32V003 J4M6 (8 pol.) 08.10.2025 R. Seelig -------------------------------------------------------- */ /* CH32V003 J4M6 +---------+ PD6 / A6 / urx / T2CH3_/ utx_ | 1 8 | PD4 / A7 / UCK / T2CH1ETR PA1 / osc1 / A1 / T1CH2 / opn0 | | PD5 / A5 / utx / T2CH_ / swio / SCL_ gnd | 2 7 | PC4 / A2 / T1CH4 / MCO | | PA2 / osc0 / A0 / T1CH2N /opp0 | 3 6 | PC2 / AETR_ / T2CH2 / T1ETR_ AETR2 | | vdd | 4 5 | PC1 / SDA / NSS / T2CH1ETR_ / URX_ +---------+ CH32V003 A4M6 +-----------+ PC1 / sda |1 C 16| PC0 PC2 / scl |2 H 15| Vdd PC3 |3 3 14| gnd PC4 |4 2 13| PA2 / osc0 / a0 PC6 / mosi |5 V 12| PA1 / osc1 / a1 PC7 / miso |6 0 11| nrst / PD7 PD1 / swio |7 0 10| PD6 / a6 / urx PD4 / a7 |8 3 9| PD5 / a5 / utx +-----------+ Pins, vorhanden mit A4M6 (16 pol.) jedoch nicht mit J4M6 (8 pol.) - PC0 - PC3 - PC6 - PC7 - PD4 - PD5 - PD7 / nrst - PA1 / PD6 sind zusammen gefuehrt, mit 8 pol. Variante nur einer fuer Hardware verwendbar ACHTUNG: bei Verwendung von PD4 und PD5 darf ein Programm unter keinen Umstaenden auf einen 8 pol. Chip geflasht werden, da dort auch der SWIO-Port ist und, so dort PD4 oder PD5 als Ausgang definiert ist ein Flashen danach nicht mehr moeglich ist */ #include "ch32fun.h" #include "ch32v003_gpio.h" #include "adc_polling.h" #define outa_init() PC1_output_init() #define outa_set() PC1_set() #define outa_clr() PC1_clr() #define outb_init() PC2_output_init() #define outb_set() PC2_set() #define outb_clr() PC2_clr() #define outab_init() { outa_init(); outb_init(); } #define butup_init() { PC4_set(); PC4_input_init(); } #define is_butup() ( !(is_PC4()) ) // Analoganschluss fuer Potentiometer ist auf PA2, wird aber ueber die // Funktion adc_init() initialisiert #define square_init() PD6_output_init() #define square_set() PD6_set() #define square_clr() PD6_clr() volatile uint32_t clkspeed = 0; uint8_t range = 0; /* -------------------------------------------------------- timer2_init initialisiert Timer2 fuer einen Compare-Match- Betrieb im Interruptmodus. Uebergabe: prescale : Taktteiler des Corecodes zum Zaehlers. cmp_match : Compare-Match (hier Autoreloadwert) bei dem der Zaehler ueberlaeuft und einen Interrupt ausloest Bsp.: 48 MHz Coretakt, Prescale 48000 bedeutet 1 KHz Timer Takt = 1 ms cmp_match 999 bedeutet 0..999 = 1000 Takte bis zum Interruptintervall Hier: Prescale == 48 cmp_match == 49 resultierender Intervall 20 KHz = 50 u_ms -------------------------------------------------------- */ void timer2_init(uint16_t prescale, uint16_t cmp_match) { RCC->APB1PCENR |= (RCC_APB1Periph_TIM2); TIM2->CTLR1 |= TIM_CKD_DIV1; TIM2->PSC= prescale; TIM2->ATRLR= cmp_match; TIM2->SWEVGR |= TIM_UG; TIM2->DMAINTENR |=(TIM_IT_Update); TIM2->CTLR1 |= TIM_CEN; NVIC_SetPriority(TIM2_IRQn,5); NVIC_EnableIRQ(TIM2_IRQn); } /* -------------------------------------------------------- TIM2_IRQHandler Code nach TIM_IT_UPDATE wird hier mit der Anzahl Mikrosekunden abgearbeitet, die in cmp_match des timer2_init angegeben ist. Hier jede 0.5 ms -------------------------------------------------------- */ void TIM2_IRQHandler() __attribute__( ( interrupt() ) ); void TIM2_IRQHandler() { static uint32_t tintcx= 0; static int clkflag= 0; tintcx++; if (tintcx >= clkspeed) { clkflag = clkflag ^ 1; if (clkflag) { square_set(); } else { square_clr(); } tintcx= 0; } TIM2->INTFR &=~(uint16_t)TIM_IT_Update; } /* -------------------------------------------------------- statled_set schaltet eine von 4 LED mittels 2 Ausgangpins ein Uebergabe: val: auszugebender Wert -------------------------------------------------------- */ void statled_set(uint8_t val) { if (val & 0x01) { outa_set(); } else { outa_clr(); } if (val & 0x02) { outb_set(); } else { outb_clr(); } } /* -------------------------------------------------------- range_get -------------------------------------------------------- */ void range_get(void) { uint8_t change_timerinit; change_timerinit= 0; if (is_butup()) { delay(50); while(is_butup()); // warten bis Taster losgelassen wird delay(50); range++; range %= 4; statled_set(range); change_timerinit= 1; } if (change_timerinit) { switch (range) { // Range 0 und 1 haben dieselbe Timerinitialisierung case 0 : case 1 : timer2_init(48, 49); // 20 KHz break; case 2 : timer2_init(48, 5); break; case 3 : timer2_init(5,3); break; default : break; } } } /* -------------------------------------------------------- main -------------------------------------------------------- */ int main(void) { int adc_value; float r; uint8_t i; SystemInit(); outab_init(); /* // Test des Tasters while(1) { if (is_butup()) { statled_set(1); } else { statled_set(0); } delay(100); } // Test der Led-Anzeige fuer Funktionstest i= 0; while(1) { statled_set(i); i++; delay(300); i %= 4; } */ butup_init(); square_init(); range= 0; // Timer fuer Range 0 => 0,5 .. 20 Hz timer2_init(48, 49) ; // 20 KHz clkspeed= 10; // Initialisieren des ADC-Wandlers, // Messwert hier an PA2 adc_init(adc_on_PA2); statled_set(range); while(1) { adc_value= 0; // Mittelwert bilden for (i= 0; i< 100; i++) { delay(3); adc_value+= adc_get(); } adc_value= adc_value / 100; // bei invertiertem Drehsinn angeschlossener Poti adc_value = 1023-adc_value; // r= ((( (524288.0f / ((float) adc_value + 25.6f)) ) / 2.048f)) * 2.0f; // fuer TimerInit 48,49 => 0.5 .. 20 Hz // r= ((( (52428.0f / ((float) adc_value + 25.6f)) ) / 2.048f)) * 2.0f; // fuer TimerInit 48,49 => 5 .. 200 Hz // r= ((( (40000.0f / ((float) adc_value + 25.6f)) ) / 2.048)) * 2.0f; // fuer TimerInit 48,5 => 55 .. 2 KHz // r= ((( (20000.0f / ((float) adc_value + 25.6f)) ) )) * 1.0f; // fuer TimerInit 5,3 => 550 .. 20 KHz switch (range) { case 0 : r= ((( (524288.0f / ((float) adc_value + 25.6f)) ) / 2.048f)) * 2.0f; // fuer TimerInit 48,49 => 0.5 .. 20 Hz break; case 1 : r= ((( (52428.0f / ((float) adc_value + 25.6f)) ) / 2.048f)) * 2.0f; // fuer TimerInit 48,49 => 5 .. 200 Hz break; case 2 : r= ((( (43778.0f / ((float) adc_value + 25.6f)) ) / 2.048)) * 2.0f; // fuer TimerInit 48,5 => 55 .. 2 KHz break; case 3 : r= ((( (21380.0f / ((float) adc_value + 25.6f)) ) )) * 1.0f; // fuer TimerInit 5,3 => 550 .. 20 KHz break; default : break; } clkspeed= (uint32_t) r; range_get(); } }