Вольт Ампер Ватт метр
- Войдите на сайт для отправки комментариев
Появилась идея сделать трехфазный измеритель электроэнергии. За основу был взят проект https://habr.com/ru/post/384597/ . Но я использовал вместо Atmega 1280 Blue Pill с процессором STM32F103C8T6 . Экран TFT 3.5' 320x480 с контролером ILI9488 . Тачскрин в данном проекте не использовал. Экран подключен на второй канал SPI . Частота 36 Мгц. Сигнал LED подключен к +3.3В. Измеряемое напряжение трех фаз 220 Вольт через делители 1-3 (680 кОм + 680 кОм + 1 Мом ) и 10 кОм подаются на входы PA0, PA2, PA4 относительно средней точки созданой делителем 4 из двух резисторов 200 Ом между корпусом и +3.3 В. (Сигнал снимается с резистора 10 кОм. Второй вывод резистора 10 кОм подключен к средней точке делителя 4. На входы PA1, PA3, PA5 будут подаваться напряжение с трансформаторов тока или датчиков Хола. Сейчас коэффициенты рассчитаны под датчик Хола 20 А. Устанавливаются в этих строках urms[j] = sqrt(utemp[j])*0.19; irms[j] = sqrt(itemp[j])/100; Про АЦП и таймеры читал статьи http://mypractic.ru/urok-26-acp-stm32-obshhie-svedeniya-rezhimy-ustanovka-konfiguracii-cherez-registry-cmsis.html
В программе подключены оба АЦП. Два регулярных канала и четыре инжектированных. Время выборки 41.5 цикл выбрано исходя из того чтобы можно было входной делитель сделать высокоомным. Итого шесть каналов измеряется за 14.5 мкс. в цикле 200 мкс . После накопления 4096 измерений (0.8 сек) таймер останавливается проводится вычисление результатов и вывод на экран. После паузы 2 сек включается таймер и цикл повторяется. Вид экрана

Сигнал подавал с генератора сделанного по мотивам генератора Dimaxa на AD9833 - 2 штуки синфазные и Si5351 с сенсорным управлением. Если кого то заинтересует код могу выложить 
#include "SPI.h"
#include <Adafruit_GFX.h>
#include <ILI9488.h>
#include <libmaple/dac.h>
#define TFT_CS PB12
#define TFT_DC PB6
#define TFT_LED PA9
#define TFT_RST PB7
ILI9488 tft = ILI9488(TFT_CS, TFT_DC, TFT_RST);
int i,j;
int res[6];
unsigned long t_prev;
unsigned long t_now;
byte flag=0;
//save current voltage data
double urms[3], utemp[3] ;
int umoment[3], umoment_old[3] ;
//save current current data
double irms[3], itemp[3];
int imoment[3] ,imoment_old[3];
//number of tick from 0 to 4095
int N = 0;
//zero-cross dfetection for frequency calc
long voltage_zerocross[3], voltage_zerocross_old[3], signalperiod[3];
//zero-cross detection for phase calc
long current_zerocross[3], phaseperiod[3];
float S[3], P[3], Q[3];
float frequency[3];
float phase[3];
void setup() {
Serial.begin(9600);
pinMode(PB12, OUTPUT);
pinMode(PA9, OUTPUT);
pinMode(PC13, OUTPUT);
pinMode(PB7, OUTPUT);
SPI.setModule(2);// выбор SPI2
tft.begin();
tft.setRotation(0);
tft.setTextColor(ILI9488_WHITE); tft.setTextSize(2);
tft.fillScreen(ILI9488_BLACK);
tft.println("Hello World!");
// установки таймера 2 на период 200 мкс
RCC_BASE->APB1ENR|= (1<<0);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4
RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM2EN; // разрешение тактирования таймера
TIMER2_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB
TIMER2_BASE->PSC = 719; // 10 мкс
TIMER2_BASE->ARR = 19; // * 20
TIMER2_BASE->DIER |= (1<<0);
timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, my_int);
TIMER2_BASE->CR1 |= (1<<0);
// ADC1, ADC2
// пины PA0-PA7 аналог
GPIOA_BASE->CRL=0x00000000;
// разрешение тактирование АЦП
RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1
RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2
// предделитель АЦП = 10 (/6)
RCC_BASE->CFGR &= ~(1<<14);
RCC_BASE->CFGR |= (1<<15);
ADC1_BASE->SMPR2 = 0b00000000000000100100100100100100;
// 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924
ADC2_BASE->SMPR2 = 0b00000000000000100100100100100100;
// 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924
ADC1_BASE->SQR1 = 0x00000000;//1канал 0b00000000000100000000000000000000; 2 каналов - 0x00100000
ADC1_BASE->SQR3 = 0x00000000;
//0канал 0b00000000000000000000000000100000; последовательность канал 0-1 0x00000020
ADC2_BASE->SQR1 = 0x00000000;//1канал
ADC2_BASE->SQR3 = 0x00000001;//1канал
ADC1_BASE->JSQR = 0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800
ADC2_BASE->JSQR = 0b00000000001100101001000000000000; // 4 инжектир. канала 4,5 =0x000329000
// включить ADC1 011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART
//CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15)
ADC1_BASE->CR2 = 0x00000000;
ADC2_BASE->CR2 = 0x00000000;
ADC1_BASE->CR2 |= (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17);
// | (1<<15) | (1<<14) | (1<<13) | (1<<12);
ADC2_BASE->CR2 |= (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17);
ADC1_BASE->CR1 |= (1<<8) | (1<<10) | (1<<16);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16
ADC2_BASE->CR1 |= (1<<8) | (1<<10) ;
ADC1_BASE->CR2 |= (1<<0);// включение ADC1
ADC2_BASE->CR2 |= (1<<0);// включение ADC2
delay(1);
//калибровка
ADC1_BASE->CR2 |= (1<<2);
ADC2_BASE->CR2 |= (1<<2);
while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки
tft.fillScreen(ILI9488_BLACK);
tft.println("Hello World!");
tft.println(RCC_BASE->CFGR,HEX);
}
void loop(void) {
if(flag){
//has new data
tft.fillScreen(ILI9488_BLACK);
tft.setCursor(0, 0);
tft.setTextSize(2);
tft.setTextColor(ILI9488_WHITE);
tft.println("VOLT AMPER WATT METER");
tft.println();
for(j=0;j<3;j++)
{
if(j == 0)tft.setTextColor(ILI9488_YELLOW);
if(j == 1)tft.setTextColor(ILI9488_GREEN);
if(j == 2)tft.setTextColor(ILI9488_ORANGE);
frequency[j] = 5000 / ((float)(signalperiod[j]));
phase[j] = (2*3.1416) * phaseperiod[j] / signalperiod[j];
S[j] = urms[j] * irms[j];
P[j] = S[j] * cos (phase[j]);
Q[j] = S[j] * sin (phase[j]);
flag = 0;
tft.setTextSize(4);
tft.print(" Pfaze "); tft.println(j+1);
tft.setTextSize(2);
tft.println();
tft.setTextSize(3);
tft.print("U="); tft.print(urms[j]);
tft.print(" I="); tft.println(irms[j]);
tft.print("F="); tft.print(frequency[j],1);
tft.print(" cos="); tft.println(cos(phase[j]),2);
tft.print("S="); tft.print(S[j],0);
tft.print(" P="); tft.print(P[j],0);
tft.print(" Q="); tft.println(Q[j],0);
// tft.setTextSize(2);
tft.println();
}
delay(2000);
TIMER2_BASE->CR1 |= (1<<0);
}
}
void my_int(){
ADC1_BASE->CR2 |= ADC_CR2_SWSTART;
while(!(ADC1_BASE->SR & ADC_SR_EOC)) ;
res[0] = ADC1_BASE->DR;
res[1] = ADC2_BASE->DR;
while(!(ADC1_BASE->SR & ADC_SR_JEOC)) ;
res[2] = ADC1_BASE->JDR1;
res[3] = ADC1_BASE->JDR2;
res[4] = ADC2_BASE->JDR3;
res[5] = ADC2_BASE->JDR4;
ADC1_BASE->SR &= ~ADC_SR_JEOC; // сброс флага
ADC1_BASE->CR2 &= ~ADC_CR2_SWSTART;
for(j=0;j<3;j++){
umoment[j] = res[2*j] - 2020;
utemp[j] = utemp[j] + pow((double)(umoment[j]),2)/4096;
//zero-crossdetect
if ((umoment_old[j] <= 0) && (umoment[j] > 0)){
voltage_zerocross[j] = N;
signalperiod[j] = voltage_zerocross[j] - voltage_zerocross_old[j];
if (signalperiod[j] < 0){
signalperiod[j] = 4096 - signalperiod[j];
}//calc signal period in ticks
voltage_zerocross_old[j] = voltage_zerocross[j];
}
umoment_old[j] = umoment[j];
imoment[j] = res[1+2*j] - 2020;
itemp[j] = itemp[j] + pow((double)(imoment[j]),2)/4096;
if ((imoment_old[j] <= 0) && (imoment[j] > 0)){
phaseperiod[j] = N - voltage_zerocross[j];
if (phaseperiod[j] < 0){
phaseperiod[j] = 4096 - phaseperiod[j];
}//calc phase period in ticks
}
imoment_old[j] = imoment[j];
}
N++;
if (N == 4095){
TIMER2_BASE->CR1 &= ~(1<<0);
//calc final result
for(j=0;j<3;j++){
urms[j] = sqrt(utemp[j])*0.19;
irms[j] = sqrt(itemp[j])/100;
utemp[j] = 0;
itemp[j] = 0;
}
N = 0; flag = 1;
if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13);
else GPIOC_BASE->ODR |= (1 << 13);
}
}
Поправил код. Планирую в дальнейшем добавить запись на SD и считать мощность. Входы процессора РА0-РА5 нужно защитить диодами.
#include "SPI.h" #include <Adafruit_GFX.h> #include <ILI9488.h> #include <libmaple/dac.h> #define TFT_CS PB12 #define TFT_DC PB6 #define TFT_LED PA9 #define TFT_RST PB7 ILI9488 tft = ILI9488(TFT_CS, TFT_DC, TFT_RST); unsigned long t_prev, t_now; byte flag=0, flag_0 =0, flag_stop =1, N_D=0, flag_st; //save current voltage, current data double urms[3], utemp[3],irms[3], itemp[3] ; int umoment[3], umoment_old[3], imoment[3] ,imoment_old[3] ; //N-number of tick from 0 to 4999 int N = 0, i,j, k; int res[6]; //zero-cross detection for frequency and phase calc long voltage_zerocross[3], voltage_zerocross_old[3], signalperiod[3]; long current_zerocross[3], phaseperiod[3]; float S[3], P[3], Q[3], frequency[3], phase[3]; void setup() { Serial.begin(9600); pinMode(PB12, OUTPUT); pinMode(PA9, OUTPUT); pinMode(PC13, OUTPUT); pinMode(PB7, OUTPUT); SPI.setModule(2);// выбор SPI2 timer_set (); adc_set () ; tft.begin(); tft.setRotation(0); tft.setTextColor(ILI9488_WHITE); tft.setTextSize(2); tft.fillScreen(ILI9488_BLACK); tft.println("Hello World!"); } void loop(void) { if(flag_0 & flag_stop){ flag_0 = 0; ADC1_BASE->CR2 |= ADC_CR2_SWSTART; while(!(ADC1_BASE->SR & ADC_SR_EOC)) ; res[0] = ADC1_BASE->DR; res[1] = ADC2_BASE->DR; while(!(ADC1_BASE->SR & ADC_SR_JEOC)) ; res[2] = ADC1_BASE->JDR1; res[3] = ADC1_BASE->JDR2; res[4] = ADC2_BASE->JDR3; res[5] = ADC2_BASE->JDR4; ADC1_BASE->SR &= ~ADC_SR_JEOC; // сброс флага ADC1_BASE->CR2 &= ~ADC_CR2_SWSTART; for(j=0;j<3;j++){ umoment[j] = res[2*j] - 2020; utemp[j] = utemp[j] + pow((double)(umoment[j]),2)/5000; //zero-crossdetect if ((umoment_old[j] <= 0) && (umoment[j] > 0)){ voltage_zerocross[j] = N; signalperiod[j] = voltage_zerocross[j] - voltage_zerocross_old[j]; if (signalperiod[j] < 0){ signalperiod[j] = 5000 - signalperiod[j]; }//calc signal period in ticks voltage_zerocross_old[j] = voltage_zerocross[j]; } umoment_old[j] = umoment[j]; imoment[j] = res[1+2*j] - 2020; itemp[j] = itemp[j] + pow((double)(imoment[j]),2)/5000; if ((imoment_old[j] <= 0) && (imoment[j] > 0)){ phaseperiod[j] = N - voltage_zerocross[j]; if (phaseperiod[j] < 0){ phaseperiod[j] = 5000 - phaseperiod[j]; }//calc phase period in ticks } imoment_old[j] = imoment[j]; } N++; if (N == 4999){ N_D++; //calc final result for(j=0;j<3;j++){ urms[j] = sqrt(utemp[j])*0.19; irms[j] = sqrt(itemp[j])/100; utemp[j] = 0; itemp[j] = 0; } N = 0; flag = 1; } } if(flag & (N_D == 2)){ flag_stop = 0; N_D = 0; //has new data tft.fillScreen(ILI9488_BLACK); tft.setCursor(0, 0); tft.setTextSize(2); tft.setTextColor(ILI9488_WHITE); tft.println("VOLT AMPER WATT METER"); tft.println(); for(j=0;j<3;j++) { if(j == 0)tft.setTextColor(ILI9488_YELLOW); if(j == 1)tft.setTextColor(ILI9488_GREEN); if(j == 2)tft.setTextColor(ILI9488_ORANGE); frequency[j] = 5000 / ((float)(signalperiod[j])); phase[j] = (2*3.1416) * phaseperiod[j] / signalperiod[j]; S[j] = urms[j] * irms[j]; P[j] = S[j] * cos (phase[j]); Q[j] = S[j] * sin (phase[j]); flag = 0; tft.setTextSize(4); tft.print(" Pfaze "); tft.println(j+1); tft.setTextSize(2); tft.println(); tft.setTextSize(3); tft.print("U="); tft.print(urms[j]); tft.print(" I="); tft.println(irms[j]); tft.print("F="); tft.print(frequency[j],1); tft.print(" cos="); tft.println(cos(phase[j]),2); tft.print("S="); tft.print(S[j],0); tft.print(" P="); tft.print(P[j],0); tft.print(" Q="); tft.println(Q[j],0); tft.println(); } flag_st = 1; } if((flag_st == 1)&(k==0)) flag_stop = 1; } void my_int(){ flag_0 = 1; k++; if(k==4999) { (k = 0); if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13); else GPIOC_BASE->ODR |= (1 << 13);} } void timer_set (){ // установки таймера 2 на период 200 мкс RCC_BASE->APB1ENR|= (1<<0);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4 RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM2EN; // разрешение тактирования таймера TIMER2_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB TIMER2_BASE->PSC = 719; // 10 мкс TIMER2_BASE->ARR = 19; // * 20 TIMER2_BASE->DIER |= (1<<0); timer_attach_interrupt(TIMER2, TIMER_UPDATE_INTERRUPT, my_int); TIMER2_BASE->CR1 |= (1<<0); } void adc_set () { // ADC1, ADC2 // пины PA0-PA7 аналог GPIOA_BASE->CRL=0x00000000; // разрешение тактирование АЦП RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1 RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2 // предделитель АЦП = 10 (/6) RCC_BASE->CFGR &= ~(1<<14); RCC_BASE->CFGR |= (1<<15); ADC1_BASE->SMPR2 = 0b00000000000000100100100100100100; // 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924 ADC2_BASE->SMPR2 = 0b00000000000000100100100100100100; // 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924 ADC1_BASE->SQR1 = 0x00000000;//1канал 0b00000000000100000000000000000000; 2 каналов - 0x00100000 ADC1_BASE->SQR3 = 0x00000000; //0канал 0b00000000000000000000000000100000; последовательность канал 0-1 0x00000020 ADC2_BASE->SQR1 = 0x00000000;//1канал ADC2_BASE->SQR3 = 0x00000001;//1канал ADC1_BASE->JSQR = 0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800 ADC2_BASE->JSQR = 0b00000000001100101001000000000000; // 4 инжектир. канала 4,5 =0x000329000 // включить ADC1 011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART //CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15) ADC1_BASE->CR2 = 0x00000000; ADC2_BASE->CR2 = 0x00000000; ADC1_BASE->CR2 |= (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); // | (1<<15) | (1<<14) | (1<<13) | (1<<12); ADC2_BASE->CR2 |= (1<<22) | (1<<21) | (1<<20) | (1<<19) | (1<<18) | (1<<17); ADC1_BASE->CR1 |= (1<<8) | (1<<10) | (1<<16);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16 ADC2_BASE->CR1 |= (1<<8) | (1<<10) ; ADC1_BASE->CR2 |= (1<<0);// включение ADC1 ADC2_BASE->CR2 |= (1<<0);// включение ADC2 delay(1); //калибровка ADC1_BASE->CR2 |= (1<<2); ADC2_BASE->CR2 |= (1<<2); while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки }Продолжил изучать АЦП . Мне нужно два быстрых канала для оцифровки сигнала. В результате поиска в интернете попал на сайт https://www.gameinstance.com/post/79/STM32-Oscilloscope
Использовал идею установить тактирование АЦП частотой 36 Мгц . При этом все чудненько работает. Разрешение конечно не 12 бит, но сигнал 500 кГц выглядит так. Тут работают два АЦП со сдвигом 7 тактов. Вывод на экран растянут.
Фото с пленкой на экране хорошим не получается. Код для Блюпил с экраном ILI9341 3.2" под спойлером. Данные с двух АЦП через 1 канал DMA1 запмсываются в буфер. Код это просто заготовка. Учился управлять АЦП и DMA через регистры. Далее с этого можно делать двухканальный осциллограф .
#include "Adafruit_GFX.h" #include "Adafruit_ILI9341.h" #include <libmaple/dma.h> #include <XPT2046_Touchscreen.h> #include "SPI.h" // Touchs creen #define CS_PIN PA4 #define TIRQ_PIN PB0 // For the Adafruit shiel , these are the default. #define TFT_DC PB1 #define TFT_CS PB11 #define TFT_RST PB10 //Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); XPT2046_Touchscreen ts(CS_PIN,255);// TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling bool dma1_ch1_Active =1; int buf_size = 1024; uint32_t data32[1024]; int i; volatile int k; int devider =2; int dualMode =1;//0-одновременно 1-сдвиг на 7 тактов int continue_ =1; int cycl = 1; //1-1.5 cycl 0- 7.5 cycl void setup() { pinMode(PB11,OUTPUT); pinMode(PA4,OUTPUT); pinMode(PC13, OUTPUT); timer3_set (); adc_set(); dma_init(); dma1_ch1_Active = 1; DMA1_BASE->CCR1 |= (1<<0);// 0-вкл.DMA1 // dma_enable(DMA1, DMA_CH1); tft.begin(); tft.setRotation(1); tft.fillScreen(ILI9341_BLACK); tft.setCursor(0, 0); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.print("DMA_test2"); } void loop() { if(dma1_ch1_Active ==0){ for(i=0; i<buf_size;i++){ int32_t d32_2 = ((data32[i]&0xFFFF0000)>>20); int d_2 = d32_2 ; tft.drawPixel(10*i,d_2+20,ILI9341_YELLOW); int32_t d32_1 = (data32[i]&0xFFFF)>>4; int d_1 = d32_1; tft.drawPixel(10*i+5,d_1+20,ILI9341_WHITE); tft.drawPixel(2*d_2+100,2*d_1+100,ILI9341_RED); } } } static void DMA1_CH1_Event() { dma1_ch1_Active = 0; } void my_int(){ k++; if(k==2499) { (k = 0); if(GPIOC_BASE->IDR&(1 << 13)) GPIOC_BASE->ODR &= ~(1<<13); else GPIOC_BASE->ODR |= (1 << 13);} } void adc_set (void) { // ADC1, ADC2 // пины PA0-PA7 аналог // GPIOA_BASE->CRL=0x00000000; // пины PA0-PA1 аналог GPIOA_BASE->CRL &= ~((1<<1) | (1<<0)); // разрешение тактирование АЦП RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC1EN; //= E30 разрешение тактирования АЦП 1 RCC_BASE->APB2ENR |= RCC_APB2ENR_ADC2EN; // разрешение тактирования АЦП 2 // предделитель АЦП = 10 (/6) if(devider == 2){RCC_BASE->CFGR &= ~(1<<14); RCC_BASE->CFGR &= ~(1<<15);} if(devider == 4){RCC_BASE->CFGR &= ~(1<<15); RCC_BASE->CFGR |= (1<<14);} if(devider == 6){RCC_BASE->CFGR &= ~(1<<14); RCC_BASE->CFGR |= (1<<15);} if(devider == 8){RCC_BASE->CFGR |= (1<<15); RCC_BASE->CFGR |= (1<<14);} ADC1_BASE->SMPR2 = 0x00009249; // 0b00000000000000100100100100100100; //1.5cycl 0x00 7.5cycl=6 mks 0x00009249 13,5cycl=0x00012492 41,5cycl=14.5mks 0x00024924 ADC2_BASE->SMPR2 = 0x00009249; //0b00000000000000100100100100100100; //1.5cycl 0x00 7.5cycl=0x00009249 13,5cycl=0x00012492 41,5cycl=0x00024924 if(cycl ==1){ADC1_BASE->SMPR2 =0x0; ADC2_BASE->SMPR2 =0x0;} ADC1_BASE->SQR1 = 0x00000000;//1канал 0b00000000000100000000000000000000; 2 каналов - 0x00100000 ADC1_BASE->SQR3 = 0x00000000; //0канал 0b00000000000000000000000000100000; последовательность канал 0-1 0x00000020 ADC2_BASE->SQR1 = 0x00000000;//1канал РА0 ADC2_BASE->SQR3 = 0x00000000;//1канал вход РА1 // ADC1_BASE->JSQR = 0b00000000000100011000100000000000; // 2 инжектир. канала 2,3, =0x000118800 // ADC2_BASE->JSQR = 0b00000000001100101001000000000000; // 4 инжектир. канала 4,5 =0x000329000 // включить ADC1 011:-Timer 2 CC2 event (19-17) 111:-SWSTART 20-ExtTrig 21-JswStart 22-SWSTART //CONT=1 непрерывный, jextsel=111(12-14), jexttrig =1(15) extse l=19-17 ADC1_BASE->CR2 = 0x00000000; ADC2_BASE->CR2 = 0x00000000; ADC1_BASE->CR2 |= (1<<20) | (1<<19) | (1<<8); // | (1<<15) | (1<<14) | (1<<13) | (1<<12); (1<<22) | | (1<<18) | (1<<17) ADC2_BASE->CR2 |= (1<<20) | (1<<19) ; ADC1_BASE->CR1 |= (1<<5) | (1<<17) | (1<<18);//=10500 //SCAN =8 JAUTO = 10 DUALMOD = 16-19 ADC2_BASE->CR1 |= (1<<5); if(dualMode ==1){ADC1_BASE->CR1 |= (1<<16);} if(continue_ ==1){ADC1_BASE->CR2 |= (1<<1); ADC2_BASE->CR2 |= (1<<1);} ADC1_BASE->CR2 |= (1<<0) ;// включение ADC1 ADC2_BASE->CR2 |= (1<<0) ;// включение ADC2 delay(1); //калибровка ADC1_BASE->CR2 |= (1<<2); ADC2_BASE->CR2 |= (1<<2); while ((ADC1_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки while ((ADC2_BASE->CR2 & 0x00000004) != 0) ; // ожидание окончания калибровки } void dma_init(void){ RCC_BASE->AHBENR |= (1<<0); // dma_init(DMA1); DMA1_BASE->CCR1 |= (1<<13) | (1<<11) | (1<<9) | (1<<7) | (1<<1); // dma_init(DMA1); // 1-прерыв по оконч. 5-циркулярная запись. // dma_setup_transfer(DMA1, DMA_CH1, &ADC1->regs->DR, DMA_SIZE_32BITS, data32, DMA_SIZE_32BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT)); // TRNS_CMPLT прерыв. по заполнению буфера MINC_MODE - автоинкремент памяти DMA1_BASE->CPAR1 = (uint32_t) &ADC1->regs->DR; //адрес регистра ADC1 DMA1_BASE->CMAR1 = (uint32_t) &data32; //адрес буфера DMA1_BASE->CNDTR1 |= (1<<10); // dma_set_num_transfers(DMA1, DMA_CH1, BUFFER_SIZE); dma_attach_interrupt(DMA1, DMA_CH1, DMA1_CH1_Event); } void adc_dma_enable(const adc_dev * dev) { // bb_peri_set_bit(&dev->regs->CR2, ADC_CR2_DMA_BIT, 1); } void timer3_set (){ // установки таймера 3 на период 200 мкс RCC_BASE->APB1ENR|= (1<<1);//включить тактирование tim-2 |(1<<1)|(1<<2); //включить тактирование tim-3,4 RCC_BASE-> APB1ENR |= RCC_APB1ENR_TIM3EN; // разрешение тактирования таймера TIMER3_BASE->SMCR &= ~((1<<0) | (1<<1) | (1<<2)); // внутреннее тактирование, шина APB TIMER3_BASE->PSC =719; // 10 мкс TIMER3_BASE->ARR =19; // * 20 TIMER3_BASE->DIER |= (1<<0); TIMER3_BASE->CR2 &= ~(1<<4) | (1<<6); //разрешение TRGO TIMER3_BASE->CR2 |= (1<<5); timer_attach_interrupt(TIMER3, TIMER_UPDATE_INTERRUPT, my_int); TIMER3_BASE->CR1 |= (1<<0); //start TIMER3 }Поскольку мы в той или иной мере метеозависимы сделал себе часы с барометром с трехдневной памятью и таймером для кухонных нужд. Управление энкодером. Внизу любимый осциллограф.
Возился с часами на Блюпил. В результате написал код для установки часов и преобразования в формат - (год,месяц,день, час, минута , секунда) без сторонней библиотеки. Начало 1 января 2021 года.
#include <libmaple/iwdg.h> #include <libmaple/dma.h> #include<libmaple/nvic.h> #include <RTClock.h> RTClock rt (RTCSEL_LSE); int month_[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; uint32 tt, count, d_ ; int year_now = 2021; int month_now = 5; int day_now = 17; int hour_now = 23; int min_now = 16; int sec_now = 0; int i,j,j_max, d_month =0, d_year =0, d_now, m_now, y_now; void setup() { pinMode(PC13, OUTPUT); Serial.begin(115200); tt = RTC_BASE->CNTH <<16 | RTC_BASE->CNTL; if(tt==0) RTC_set (); } void loop() { if (rt.getTime()!=tt){ kalk_time(); Serial.print(y_now); Serial.print("/"); Serial.print(m_now); Serial.print("/"); Serial.print(d_now+1);Serial.print("-"); Serial.print(hour_now); Serial.print(":"); Serial.print(min_now); Serial.print(":"); Serial.println(sec_now); } } void RTC_set () { if((year_now % 4) == 0) {month_[1] = 29;} j_max = year_now - 2021; if(j_max > 0){ for(j=0; j<j_max; j++) {if(j%4 == 3){d_year = d_year +366;} else{ d_year = d_year + 365;} } } for(i=0; i<(month_now-1);i++) { d_month = d_month + month_[i];} count = 1609459200+(d_year + d_month + day_now-1)*86400 + hour_now*3600 + min_now*60 + sec_now; RTC_BASE->CRL |= RTC_CRL_CNF; //Разрешить Запись в регистры RTC RTC_BASE->CNTH = count>>16; //записать новое значение счетного регистра RTC_BASE->CNTL = count; RTC_BASE->CRL &= ~RTC_CRL_CNF; //Запретить запись в регистры RTC //if (rt.getTime()==0) { rt.setTime(count);} //записать новое значение счетного регистра если 0 } void kalk_time(void){ tt = RTC_BASE->CNTH <<16 | RTC_BASE->CNTL; // чтение счетного регистра d_ = (tt - 1609459200)/86400; d_now = d_; d_ = (tt - 1609459200)%86400; sec_now = d_ % 60; hour_now = d_ / 3600; d_ = d_ % 3600; min_now = d_ / 60; i = 0; j = 0; while(d_now > (month_[i]-1)) {if(j%4 ==3){month_[1] = 29;}else {month_[1] = 28;} d_now = d_now - month_[i]; i++; if(i == 12){i=0; j++;} } m_now = i+1; y_now = j+2021; //rt.getTime(); //чтение счетного регистра // Serial3.print("time is: "); Serial3.println(tt); }