Sommario:
- Passaggio 1: hardware
- Passaggio 2: costruire
- Passaggio 3: programmi
- Passaggio 4: Informazioni sul codice
- Passaggio 5: Main.h
- Passaggio 6: Main.c
Video: Oscilloscopio a quattro bit: 6 passaggi
2024 Autore: John Day | [email protected]. Ultima modifica: 2024-01-30 10:03
È un progetto per divertimento solo per vedere fino a che punto in velocità potrei spingere un display a matrice di punti MAX7219. E invece di fargli eseguire il "gioco della vita", ho deciso di farne uno "scope". Come capirai dal titolo, questo non è un sostituto di un vero oscilloscopio:-).
Dato che non ho intenzione di usarlo in alcun modo serio, non realizzerò un circuito stampato per questo. Forse, solo forse lo metterò su una perf-board ma per ora è, e rimarrà, su una breadboard. Inoltre non c'è un amplificatore/attenuatore di ingresso, devi fornire un segnale compreso tra 0 e 3,3V, non andare in negativo o oltre 3,3V poiché potresti danneggiare il microcontrollore.
Passaggio 1: hardware
È economico, molto economico quando si acquistano le parti in Cina tramite ebay o siti simili. Utilizza una scheda di sviluppo STM32F103C8, a volte chiamata "pillola blu" che ho acquistato per circa 2 euro (o USD, hanno quasi lo stesso valore, fine 2018), due display a matrice di punti 8x8x4 con chip MAX7219, acquistati per 5 euro a pezzo e un encoder rotativo di circa 1 euro.
Ovviamente è necessario un alimentatore che fornisca 3,3 V a poche centinaia di milliampere. Il regolatore di tensione sulla scheda di sviluppo STM32F103C8 non è utilizzato, non è in grado di fornire corrente sufficiente per i display. La scheda tecnica del MAX7219 specifica che la tensione di alimentazione operativa dovrebbe essere compresa tra 4,0 e 5,5 V ma funziona bene a 3,3 V, forse non quando lo si utilizza in un ambiente molto caldo o freddo, ma a 20 gradi Celsius va bene. E ora non devo più usare convertitori di livello tra il microcontrollore ei tabelloni.
Passaggio 2: costruire
Quando guardi l'immagine potresti vedere che uso le linee elettriche sulle breadboard in modo non convenzionale, entrambe le linee in alto sono il binario positivo ed entrambi in basso sono il binario di terra. È il modo in cui sono abituato a farlo e funziona bene, rende l'installazione un po' più simile agli schemi che disegno. Inoltre, ho realizzato molte piccole schede con parti che posso collegare alla breadboard per accelerare le cose e sono tutte configurate per utilizzare le due linee superiori come positive e le linee inferiori come massa. Come ho detto, la risoluzione è di 4 bit (16 livelli), e poiché ci sono 4x8 led uno accanto all'altro ci sono solo 32 punti campione (pt). Confrontalo con un Rigol Rigol DS1054Z (8 bit e 12Mpts) e vedrai che questo non è certo un giocattolo. Quale sia la larghezza di banda effettiva, non lo so, l'ho testata fino a 10kHz e funziona bene.
Passaggio 3: programmi
L'IDE che utilizzo è Atollic TrueStudio che all'inizio di quest'anno (2018) è stato adottato da ST Micro Electronics ed è disponibile gratuitamente, senza limiti di tempo, senza limiti di dimensioni del codice, senza fastidiosi schermi. Insieme ad esso utilizzo STM32CubeMX, un programma che mi fornisce il codice di partenza e genera l'inizializzazione di tutte le periferiche. E ha un display di tutti i pin del microcontrollore e del loro utilizzo. Anche se non usi STM32CubeMX per generare codice, questo è molto utile. Una cosa che non mi piace è il cosiddetto HAL che è l'impostazione predefinita di STM32CubeMX. Preferisco il metodo di lavoro LowLayer.
Per programmare il microcontrollore utilizzo il programmatore/debugger ST-Link di ST Micro Electronics o il J-Link di Segger. Entrambi questi dispositivi non sono gratuiti, anche se puoi acquistarne copie cinesi per pochi euro.
Passaggio 4: Informazioni sul codice
I MAX7219 indirizzano i LED in quello che io chiamo un modo orizzontale, 8 LED uno accanto all'altro. Per un oscilloscopio 8 LED uno sopra l'altro sarebbe stato più facile, quindi ho creato un semplice frame-buffer che viene scritto con i dati in modo verticale e letto nel modo orizzontale richiesto. Il MAX7219 utilizza un codice a 16 bit per 8 LED, in cui il primo byte viene utilizzato per indirizzare la linea selezionata. E poiché ci sono quattro di questi moduli impilati uno accanto all'altro, con i loro ingressi collegati alle uscite del modulo prima di esso, devi inviare quei 16 bit quattro volte per raggiungere l'ultimo modulo. (Spero di essere stato chiaro…) I dati vengono inviati al MAX7219 tramite SPI, un protocollo semplice ma molto veloce. Questo è ciò che stavo sperimentando, quanto velocemente puoi andare a inviare i dati al MAX7219. Alla fine, sono tornato a 9 MHz appena al di sotto della velocità massima specificata dal foglio dati.
Uso due dei quattro timer disponibili dell'STM32F103C8, uno per la generazione della base dei tempi e l'altro per la lettura dell'encoder rotativo, che imposta la base dei tempi. TIMER3 genera la base tempi, lo fa dividendo l'orologio per 230, aggiornando il contatore ogni 3,2 uS. Con l'encoder rotativo è possibile selezionare per avere il conteggio del contatore da 2 impulsi di clock fino a 2000 impulsi di clock. Supponiamo che tu scelga 100. TIMER3 quindi genera un EVENTO ogni 320 uS. Questo EVENTO attiva l'ADC per registrare un campione del segnale di ingresso e, poiché ci sono 32 campioni da prendere per una schermata, questo verrà completato dopo circa. 10 ms. In 10 ms puoi adattare una lunghezza d'onda di 100 Hz o due di 200 Hz e così via. Tuttavia, superare 3 onde per schermo rende piuttosto difficile riconoscere la forma d'onda.
Per il resto posso solo rimandarti al codice, non è difficile da seguire anche se hai solo una certa esperienza con un Arduino. In effetti, potresti fare la stessa cosa con un Arduino, anche se dubito che funzionerebbe velocemente come una "pillola blu". L'STM32F103C8 è un microcontrollore a 32 bit che funziona a 72 MHz, ha due periferiche SPI e un ADC molto veloce.
Passaggio 5: Main.h
#ifndef _MAIN_H_#define _MAIN_H_
#include "stm32f1xx_ll_adc.h"
#include "stm32f1xx_ll_rcc.h" #include "stm32f1xx_ll_bus.h" #include "stm32f1xx_ll_system.h" #include "stm32f1xx_ll_exti.h" #include_stm32f1xx_ll_cortex.h" #include_xxhllputil "stm32s.f1xx include "stm32f1xx_ll_dma.h" #include "stm32f1xx_ll_spi.h" #include "stm32f1xx_ll_tim.h" #include "stm32f1xx.h" #include "stm32f1xx_ll_gpio.h"
#ifndef NVIC_PRIORITYGROUP_0
#define NVIC_PRIORITYGROUP_0 ((uint32_t)0x00000007) #define NVIC_PRIORITYGROUP_1 ((uint32_t)0x00000006) #define NVIC_PRIORITYGROUP_2 ((uint32_t)0x00000005) #define NVIC_C00000) (define NVIC_PRIORITYGROUP0x00000) (define NVIC_3PRIOR000) (int32_VIOR_PRIORITYGROUP000000)
#ifdef _cplusplus
extern "C" { #endif void _Error_Handler(char *, int);
#define Error_Handler() _Error_Handler(_FILE_, _LINE_)
#ifdef _cplusplus } #endif
#finisci se
Passaggio 6: Main.c
#include "main.h" static void LL_Init(void); void SystemClock_Config(void); vuoto statico MX_GPIO_Init(void); vuoto statico MX_ADC1_Init(void); vuoto statico MX_SPI1_Init(void); vuoto statico MX_SPI2_Init(void); vuoto statico MX_TIM3_Init(void); vuoto statico MX_TIM4_Init(void);
uint16_t SPI1_send64(uint16_t data3, uint16_t data2, uint16_t data1, uint16_t data0);
uint16_t SPI2_send64(uint16_t data3, uint16_t data2, uint16_t data1, uint16_t data0); void MAX7219_1_init(); void MAX7219_2_init(); void erase_frame_buffer(void); void fill_frame_buffer(void); void display_frame_buffer(void); void set_timebase(void);
uint8_t upper_display[4][8]; //vier bytes naast elkaar, acht onder elkaar
uint8_t lower_display[4][8]; //deze twee samen vormen de frame-buffer
uint8_t sample_buffer[32]; //buffer voor de resultaten van de ADC
int main (vuoto)
{ LL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_SPI1_Init(); MX_SPI2_Init(); MX_TIM3_Init(); MX_TIM4_Init();
LL_SPI_Enable(SPI1);
LL_SPI_Enable(SPI2);
LL_TIM_EnableCounter(TIM3);
LL_TIM_EnableCounter(TIM4);
LL_ADC_Enable(ADC1);
LL_ADC_REG_StartConversionSWStart(ADC1); LL_ADC_EnableIT_EOS(ADC1);
LL_mRitardo(500); //MAX7219 ha bisogno di un po' di tempo dopo l'accensione
MAX7219_1_init(); MAX7219_2_init();
//LL_TIM_SetAutoReload(TIM3, 9);
mentre (1)
{ set_timebase(); erase_frame_buffer(); fill_frame_buffer(); display_frame_buffer(); } }
void erase_frame_buffer(void)
{ int8_t x; int8_t y;
for (x = 0; x < 4; x++) //kolom_bytes {
for (y = 0; y < 8; y++) //lijnen { display_superiore[x][y] = 0; //tutti i bit su null lower_display[x][y] = 0; } } }
void fill_frame_buffer(void)
{ uint8_t y = 0; //tensione uint8_t tijd = 0; //tijd uint8_t display_byte; //Steeds 8 bits naast elkaar en dat 4 maal op een lijn uint8_t display_bit;
for (tijd = 0; tijd < 32; tijd++) { display_byte = tijd / 8; display_bit = 7 - (tijd % 8);
y = sample_buffer[tijd];
if (y > 7) //nel display superiore schrijven
{ display_superiore[display_byte][15-y] |= (1 << display_bit); } else //nel display inferiore schrijven { display_inferiore[display_byte][7-y] |= (1 << display_bit); } } }
void display_frame_buffer(void)
{
uint8_t y; //acht lijnen boven elkaar (per display) uint16_t yl; //numero di riferimento per MAX7219
for (y = 0; y < 8; y++) { yl = (y+1) << 8; //MAX7219 heeft lijnnummer in de superiore 8 bit e 16 bit woord
SPI2_send64((yl | upper_display[0][y]), (yl | upper_display[1][y]), (yl | upper_display[2][y]), (yl | upper_display[3][y]));
SPI1_send64((yl | display_inferiore[0][y]), (yl | display_inferiore[1][y]), (yl | display_inferiore[2][y]), (yl | display_inferiore[3][y])); }
}
void set_timebase(void)
{ uint8_t timebase_knop;
timebase_knop = LL_TIM_GetCounter(TIM4) / 2;
switch (timebase_knop)
{ caso 0: LL_TIM_SetAutoReload(TIM3, 1999); rottura; caso 1: LL_TIM_SetAutoReload(TIM3, 999); rottura; caso 2: LL_TIM_SetAutoReload(TIM3, 499); rottura; caso 3: LL_TIM_SetAutoReload(TIM3, 199); rottura; caso 4: LL_TIM_SetAutoReload(TIM3, 99); rottura; caso 5: LL_TIM_SetAutoReload(TIM3, 49); rottura; caso 6: LL_TIM_SetAutoReload(TIM3, 19); rottura; caso 7: LL_TIM_SetAutoReload(TIM3, 9); rottura; caso 8: LL_TIM_SetAutoReload(TIM3, 4); rottura; caso 9: LL_TIM_SetAutoReload(TIM3, 1); rottura;
predefinito:
LL_TIM_SetAutoReload(TIM3, 99); rottura; } }
void MAX7219_1_init()
{SPI1_send64(0x0000, 0x0000, 0x0000, 0x0000); //nop SPI1_send64(0x0C00, 0x0C00, 0x0C00, 0x0C00); //spegnimento su SPI1_send64(0x0000, 0x0000, 0x0000, 0x0000); //nop SPI1_send64(0x0F00, 0x0F00, 0x0F00, 0x0F00); //testmode disattivato SPI1_send64(0x0C01, 0x0C01, 0x0C01, 0x0C01); //spegnimento, funzionamento normale SPI1_send64(0x0900, 0x0900, 0x0900, 0x0900); //nessuna decodifica 7seg, 64 pixel SPI1_send64(0x0A07, 0x0A07, 0x0A07, 0x0A07); //intensità 50% SPI1_send64(0x0B07, 0x0B07, 0x0B07, 0x0B07); //tutte le righe su }
void MAX7219_2_init()
{SPI2_send64(0x0000, 0x0000, 0x0000, 0x0000); //nop SPI2_send64(0x0C00, 0x0C00, 0x0C00, 0x0C00); //spegnimento su SPI2_send64(0x0000, 0x0000, 0x0000, 0x0000); //nop SPI2_send64(0x0F00, 0x0F00, 0x0F00, 0x0F00); //testmode disattivato SPI2_send64(0x0C01, 0x0C01, 0x0C01, 0x0C01); //spegnimento, funzionamento normale SPI2_send64(0x0900, 0x0900, 0x0900, 0x0900); //nessuna decodifica 7seg, 64 pixel SPI2_send64(0x0A07, 0x0A07, 0x0A07, 0x0A07); //intensità 50% SPI2_send64(0x0B07, 0x0B07, 0x0B07, 0x0B07); //tutte le righe su }
uint16_t SPI1_send64(uint16_t data3, uint16_t data2, uint16_t data1, uint16_t data0)
{ LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);
LL_SPI_TransmitData16(SPI1, dati3);
mentre (LL_SPI_IsActiveFlag_TXE(SPI1) == 0) {}
LL_SPI_TransmitData16(SPI1, dati2);
mentre (LL_SPI_IsActiveFlag_TXE(SPI1) == 0) {}
LL_SPI_TransmitData16(SPI1, dati1);
mentre (LL_SPI_IsActiveFlag_TXE(SPI1) == 0) {}
LL_SPI_TransmitData16(SPI1, data0);
mentre (LL_SPI_IsActiveFlag_BSY(SPI1) == 1) {}
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);
restituisce LL_SPI_ReceiveData16(SPI1); }
uint16_t SPI2_send64(uint16_t dati3, uint16_t dati2, uint16_t dati1, uint16_t dati0)
{ LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_12);
LL_SPI_TransmitData16(SPI2, dati3);
mentre (LL_SPI_IsActiveFlag_TXE(SPI2) == 0) {}
LL_SPI_TransmitData16(SPI2, dati2);
mentre (LL_SPI_IsActiveFlag_TXE(SPI2) == 0) {}
LL_SPI_TransmitData16(SPI2, dati1);
mentre (LL_SPI_IsActiveFlag_TXE(SPI2) == 0) {}
LL_SPI_TransmitData16(SPI2, dati0);
mentre (LL_SPI_IsActiveFlag_BSY(SPI2) == 1) {}
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_12);
restituire LL_SPI_ReceiveData16(SPI2); }
void ADC1_2_IRQHandler(void)
{ statico uint8_t sample_counter; uint8_t trigger; statico uint8_t precedente_trigger;
if (LL_ADC_IsActiveFlag_EOS(ADC1) != RESET)
{ if (contatore_campione < 32) { buffer_campione[contatore_campione] = LL_ADC_REG_ReadConversionData32(ADC1) / 256; if (contatore_campione < 32) contatore_campione++; altrimenti contatore_campione = 0; } else { trigger = LL_ADC_REG_ReadConversionData32(ADC1) / 256;
if ((trigger == 7) && (previous_trigger < trigger)) //gaat niet helemaal goed bij blokgolven… { sample_counter = 0; } precedente_trigger = trigger; }
LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_13);
LL_ADC_ClearFlag_EOS(ADC1);
} }
static void LL_Init(void)
{ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
NVIC_SetPriority(MemoryManagement_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(BusFault_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(UsageFault_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(SVCall_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(DebugMonitor_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
LL_GPIO_AF_Remap_SWJ_NOJTAG();
}
void SystemClock_Config(void)
{ LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) Error_Handler(); LL_RCC_HSE_Enable(); while(LL_RCC_HSE_IsReady() != 1); LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE_DIV_1, LL_RCC_PLL_MUL_9); LL_RCC_PLL_Enable(); while(LL_RCC_PLL_IsReady() != 1); LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2); LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL); LL_Init1msTick(72000000); LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK); LL_SetSystemCoreClock(72000000); LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSRC_PCLK2_DIV_6);
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
}
vuoto statico MX_ADC1_Init(void)
{ LL_ADC_InitTypeDef ADC_InitStruct; LL_ADC_CommonInitTypeDef ADC_CommonInitStruct; LL_ADC_REG_InitTypeDef ADC_REG_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
GPIO_InitStruct. Pin = LL_GPIO_PIN_0;
GPIO_InitStruct. Mode = LL_GPIO_MODE_ANALOG; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
NVIC_EnableIRQ(ADC1_2_IRQn);
ADC_InitStruct. DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct. SequencersScanMode = LL_ADC_SEQ_SCAN_DISABLE; LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_CommonInitStruct. Multimode = LL_ADC_MULTI_INDEPENDENT;
LL_ADC_CommonInit(_LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
ADC_REG_InitStruct. TriggerSource = LL_ADC_REG_TRIG_EXT_TIM3_TRGO;
ADC_REG_InitStruct. SequencerLength = 1; ADC_REG_InitStruct. SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; ADC_REG_InitStruct. ContinuousMode = LL_ADC_REG_CONV_SINGLE; ADC_REG_InitStruct. DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE; LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_0, LL_ADC_SAMPLINGTIME_41CYCLES_5);
}
vuoto statico MX_SPI1_Init(void)
{ LL_SPI_InitTypeDef SPI_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
GPIO_InitStruct. Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_7;
GPIO_InitStruct. Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct. Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct. OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//NVIC_SetPriority(SPI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
//NVIC_EnableIRQ(SPI1_IRQn);
SPI_InitStruct. TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct. Mode = LL_SPI_MODE_MASTER; SPI_InitStruct. DataWidth = LL_SPI_DATAWIDTH_16BIT; SPI_InitStruct. ClockPolarity = LL_SPI_POLARITY_LOW; SPI_InitStruct. ClockPhase = LL_SPI_PHASE_1EDGE; SPI_InitStruct. NSS = LL_SPI_NSS_SOFT; SPI_InitStruct. BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; SPI_InitStruct. BitOrder = LL_SPI_MSB_FIRST; SPI_InitStruct. CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; SPI_InitStruct. CRCPoly = 10; LL_SPI_Init(SPI1, &SPI_InitStruct); }
vuoto statico MX_SPI2_Init(void)
{ LL_SPI_InitTypeDef SPI_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
GPIO_InitStruct. Pin = LL_GPIO_PIN_13|LL_GPIO_PIN_15;
GPIO_InitStruct. Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct. Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct. OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
//NVIC_SetPriority(SPI2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
//NVIC_EnableIRQ(SPI2_IRQn);
SPI_InitStruct. TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct. Mode = LL_SPI_MODE_MASTER; SPI_InitStruct. DataWidth = LL_SPI_DATAWIDTH_16BIT; SPI_InitStruct. ClockPolarity = LL_SPI_POLARITY_LOW; SPI_InitStruct. ClockPhase = LL_SPI_PHASE_1EDGE; SPI_InitStruct. NSS = LL_SPI_NSS_SOFT; SPI_InitStruct. BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4; SPI_InitStruct. BitOrder = LL_SPI_MSB_FIRST; SPI_InitStruct. CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; SPI_InitStruct. CRCPoly = 10; LL_SPI_Init(SPI2, &SPI_InitStruct); }
vuoto statico MX_TIM3_Init(void)
{ LL_TIM_InitTypeDef TIM_InitStruct;
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
TIM_InitStruct. Prescaler = 229;
TIM_InitStruct. CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct. Autoreload = 9; TIM_InitStruct. ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM3, &TIM_InitStruct);
LL_TIM_DisableARRPreload(TIM3);
LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL); LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_UPDATE); LL_TIM_EnableMasterSlaveMode(TIM3); }
vuoto statico MX_TIM4_Init(void)
{ LL_TIM_InitTypeDef TIM_InitStruct; LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
GPIO_InitStruct. Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
GPIO_InitStruct. Mode = LL_GPIO_MODE_FLOATING; LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
LL_TIM_SetEncoderMode(TIM4, LL_TIM_ENCODERMODE_X2_TI1);
LL_TIM_IC_SetActiveInput(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); LL_TIM_IC_SetPrescaler(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); LL_TIM_IC_SetFilter(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); LL_TIM_IC_SetActiveInput(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI); LL_TIM_IC_SetPrescaler(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); LL_TIM_IC_SetFilter(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); LL_TIM_IC_SetPolarity(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
TIM_InitStruct. Prescaler = 0;
TIM_InitStruct. CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct. Autoreload = 19; TIM_InitStruct. ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; LL_TIM_Init(TIM4, &TIM_InitStruct);
LL_TIM_DisableARRPreload(TIM4);
LL_TIM_SetTriggerOutput(TIM4, LL_TIM_TRGO_RESET); LL_TIM_DisableMasterSlaveMode(TIM4); }
vuoto statico MX_GPIO_Init(void)
{ LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_13);
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4); LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_12);
GPIO_InitStruct. Pin = LL_GPIO_PIN_13;
GPIO_InitStruct. Mode = LL_GPIO_MODE_OUTPUT; GPIO_InitStruct. Speed = LL_GPIO_SPEED_FREQ_LOW; GPIO_InitStruct. OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct. Pin = LL_GPIO_PIN_4;
GPIO_InitStruct. Mode = LL_GPIO_MODE_OUTPUT; GPIO_InitStruct. Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct. OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct. Pin = LL_GPIO_PIN_12;
GPIO_InitStruct. Mode = LL_GPIO_MODE_OUTPUT; GPIO_InitStruct. Speed = LL_GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct. OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOB, &GPIO_InitStruct); }
void _Error_Handler(char *file, int line)
{ mentre(1) { } }
#ifdef USE_FULL_ASSERT
void assert_failed (file uint8_t*, riga uint32_t)
{ } #finisci se
Consigliato:
COME REALIZZARE UNA CALCOLATRICE QUATTRO FUNZIONALE IN CPP: 6 Passaggi
COME FARE UNA CALCOLATRICE QUATTRO FUNZIONALE IN CPP: Le calcolatrici sono usate da tutti nella vita quotidiana. Una semplice calcolatrice può essere realizzata utilizzando un programma C++ in grado di sommare, sottrarre, moltiplicare e dividere due operandi inseriti dall'utente. L'istruzione if e goto viene utilizzata per creare una calcolatrice
Slider per fotocamera motorizzato fai-da-te da quattro parti stampate in 3D: 5 passaggi (con immagini)
Slider per fotocamera motorizzato fai-da-te da quattro parti stampate in 3D: Ciao creatori, è il creatore moekoe! Oggi voglio mostrarti come costruire un cursore per fotocamera lineare molto utile basato su una guida V-Slot/Openbuilds, motore passo-passo Nema17 e solo quattro parti stampate in 3D .Qualche giorno fa ho deciso di investire in una fotocamera migliore per
Progettazione di un semplice controller di cache associativa a quattro vie in VHDL: 4 passaggi
Progettazione di un semplice controller di cache associativo a quattro vie in VHDL: nel mio precedente tutorial, abbiamo visto come progettare un semplice controller di cache a mappatura diretta. Questa volta facciamo un passo avanti. Progetteremo un semplice controller di cache associativo a quattro vie. vantaggio? Meno miss rate, ma a scapito delle prestazioni
Word Clock a quattro lettere con generatore di parole Akafugu e frasi di ispirazione: 3 passaggi
Orologio di parole a quattro lettere con generatore di parole Akafugu e frasi ispiratrici: questa è la mia versione dell'orologio di parole a quattro lettere, un'idea nata negli anni '70. L'orologio visualizza una serie di parole di quattro lettere generate da un algoritmo di generazione di parole casuali o da un database di quattro lettere correlate
Come realizzare un video a schermo diviso in quattro passaggi: 4 passaggi (con immagini)
Come realizzare un video a schermo diviso in quattro passaggi: spesso vediamo una stessa persona in una scena due volte in uno spettacolo televisivo. E per quanto ne sappiamo, l'attore non ha un fratello gemello. Abbiamo anche visto che due video di canto vengono messi su uno schermo per confrontare le loro abilità canore. Questo è il potere di sp