Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43148
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av sodjan »

Om encodern ger ett absolutvärde för vinkeln/positionen så låter det inte
logiskt att ha värden som indikerar riktning. En vinkel/position är ju ett
fixt läge och har inget med rörelse att göra.

Om vi antar att vi har en viss vinkel/position som vi kallar x. Ska det då
vara +x eller -x beroende på från vilket håll encodern hamnade där?
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av DanielM »

Uint16_t kan inte hålla i negativa värden, så jag försöker istället att flytta upp ett centervärde från 0.

Jag hade tänkt mer som så här.

Här börjar jag alltså på 0x8000 och stegar mig nedåt eller uppåt.
Notera att __HAL_TIM_GetCounter(htim) återgår till 0xFFFF om jag roterar "lägre" än 0.

Kod: Markera allt

	bool encoder1_direction = !(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim));

	/* Values between 0 and 0xFFFF */
	if(encoder1_direction)
		encoder[1] = 0x8000 + __HAL_TIM_GetCounter(htim); /* Positive rotation: 0x8000 - 0xFFFF */
	else
		encoder[1] = __HAL_TIM_GetCounter(htim) - 0x8000; /* Negative rotation: 0 - 0x7FFF */
svanted
Inlägg: 5082
Blev medlem: 30 augusti 2010, 21:20:38
Ort: Umeå

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av svanted »

eller kanske använda int16 istf uint16?
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43148
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av sodjan »

> Här börjar jag alltså på 0x8000 och stegar mig nedåt eller uppåt.

Men då handlar det ju inte om "åt vilket håll som encodern roterar"
utan om var den befinner sig utifrån en tänkt centrumposition. Det
spelar alltså ingen roll *hur* encodern kom till sin aktuella position.

Det är ju två helt olika saker...

Så centrum är alltid 0x8000 oavsett om föregående läge var 0x7FFF eller 0x8001?
Det var inte så som jag tolkade din fråga.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av DanielM »

svanted skrev: 22 juni 2021, 13:47:31 eller kanske använda int16 istf uint16?
Jag har funderat på detta också. Det ligger på min lista faktiskt. Orsaken varför jag har valt som ovan har med att jag vill göra likadant på övriga funktionerna. Jag skriver nämligen ut värden igenom denna funktion.

Alla funktioner så som dessa returnerar uint16_t. Men detta sätt att skriva ut siffror på en ILI9341 LCD tar lång tid, så jag måste nog titta mer på det förslag du namnger.
Målet är att jag ska skriva ut en komplett sträng på LCD:n med mätvärden. Inte som jag gör nedan. Tar för lång tid.

Kod: Markera allt

STM32_PLC_Analog_Input_GetADC
STM32_PLC_Analog_Input_GetDADC
STM32_PLC_Digital_Input_Get
STM32_PLC_Input_Capture_Get

Kod: Markera allt

void display_values(uint8_t values_to_display, char text[], uint8_t shift_upper, uint8_t shift_lower, uint16_t (*getValue)(uint8_t));
void STM32_PLC_LCD_Show_Values() {
	// Set rotation
	ILI9341_setRotation(2);

	/* Print title */
	ILI9341_printText("Measurement values", 55, 10, COLOR_YELLOW, COLOR_NAVY, 2);

	display_values(12, "ADC%i:", 0, 20,STM32_PLC_Analog_Input_GetADC);
	display_values(5, "DADC%i:", 40, 60, STM32_PLC_Analog_Input_GetDADC);
	display_values(8, "DI%i:", 60, 80, STM32_PLC_Digital_Input_Get);
	display_values(2, "E%i:", 90, 100, STM32_PLC_Encoder_Get);
	display_values(3, "IC%i:", 100, 100, STM32_PLC_Input_Capture_Get);

}

void display_values(uint8_t values_to_display, char text[], uint8_t shift_upper, uint8_t shift_lower, uint16_t (*getValue)(uint8_t)){
	/* Initial arrays */
	char label[20];
	char float_value[10];
	uint16_t colors[6] = {(uint16_t) COLOR_RED, (uint16_t) COLOR_CYAN, (uint16_t) COLOR_ORANGE, (uint16_t) COLOR_MAGENTA, (uint16_t) COLOR_GREEN, (uint16_t) COLOR_WHITE};
	uint8_t x[6] = {55, 140, 230, 55, 140, 230};
	uint8_t y[6] = {35, 35, 35, 45, 45, 45};

	for(uint8_t i = 0; i < values_to_display; i++){
		//sprintf_(float_value, "%0.2f", getValue(i));
		sprintf(float_value, "%i", getValue(i));
		sprintf(label, text, i);
		strcat(label, float_value);
		if(i >= 0 && i <= 5)
			ILI9341_printText(label, x[i], y[i] + shift_upper, colors[i], COLOR_NAVY, 1);
		else if(i >= 6 && i <= 11)
			ILI9341_printText(label, x[i - 6], y[i - 6] + shift_lower, colors[i - 6], COLOR_NAVY, 1);
	}
}
sodjan skrev: 22 juni 2021, 13:53:49 > Här börjar jag alltså på 0x8000 och stegar mig nedåt eller uppåt.

Men då handlar det ju inte om "åt vilket håll som encodern roterar"
utan om var den befinner sig utifrån en tänkt centrumposition. Det
spelar alltså ingen roll *hur* encodern kom till sin aktuella position.

Det är ju två helt olika saker...

Så centrum är alltid 0x8000 oavsett om föregående läge var 0x7FFF eller 0x8001?
Det var inte så som jag tolkade din fråga.

Centrum är 0x8000. Men jag tror att jag ska titta mer på förslaget som svanted föreslog. Jag har tänkt på detta förut. Men ändrat mig lite.

Om C kunde ha generics så skulle det vara möjligt för mig att välja int16 direkt.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av DanielM »

En fråga som bygger på erfarenhet.

Jag har en encoder som räknar antalet positioner som ni vet. Sedan på exakt samma timer har jag en Input Capture(IC) som också ska räkna frekvens, dvs hastighet.
I detta fall går det inte att ha en encoder tillsammans med en IC. Men det går att ha en interrupt för dom båda.

Så jag har en timer på sidan om som räknar från 0x00 till 0xbb80 (48000) och jag tänkte att denna typ av period skall vara perioden.
Målet är att jag ska plocka ut T1 och T2 och jämföra dessa mot varandra T = T2 - T1 och dela f = 1/T för att få frekvensen.
Jag mäter T1 och T2 för varje gång interrupten anropas för IC.

Min timer är på 48 MHz och prescaler är på 0 samt perioden är på 0xbb80 och jag funderar på att den ska behålla perioden.
Men just prescaler måste jag dra upp lite. Om jag sätter min prescaler på 999 så får jag en timerfrekvens på 48000 Hz, då 48*10^6/(999+1) = 48000 Hz.

Borde jag inte få en IC som har då frekvensen mellan 0 till 48kHz då?

Vad tycker ni om denna kod? Den räknar ut positionen med encoder och frekvensen med input capture. Jag får konstiga värden på frekvensen dock. Ibland 334, sedan 34535 och sedan 2340 och sedan 423 osv.

Kod: Markera allt

static uint16_t encoder[2] = {0};
static uint16_t input_capture[3] = {0};
static uint16_t T1[3] = {0};
static uint16_t T2[3] = {0};
static uint8_t called_times[3] = {0};
static TIM_HandleTypeDef* counter_timer;

void STM32_PLC_Start_Counters(TIM_HandleTypeDef* htim4, TIM_HandleTypeDef* htim19, TIM_HandleTypeDef* htim14) {
	/* Encoder */
	HAL_TIM_Encoder_Start_IT(htim4, TIM_CHANNEL_ALL);
	HAL_TIM_Encoder_Start_IT(htim19, TIM_CHANNEL_ALL);
	encoder[0] = 0x8000; /* Initial settings */
	encoder[1] = 0x8000;

	/* Input Capture */
	HAL_TIM_IC_Start_IT(htim4, TIM_CHANNEL_3);
	HAL_TIM_IC_Start_IT(htim4, TIM_CHANNEL_4);
	HAL_TIM_IC_Start_IT(htim19, TIM_CHANNEL_3);
	input_capture[0] = 0; /* Initial settings */
	input_capture[1] = 0;
	input_capture[2] = 0;

	/* This timer is only made for input capture */
	HAL_TIM_Base_Start(htim14);
	counter_timer = htim14;
}

void STM32_PLC_Encoder(TIM_HandleTypeDef* htim, uint8_t i) {
	if(!(__HAL_TIM_IS_TIM_COUNTING_DOWN(htim)))
		encoder[i] = 0x8000 + __HAL_TIM_GetCounter(htim); /* Positive rotation: 0x8000 - 0xFFFF */
	else
		encoder[i] = __HAL_TIM_GetCounter(htim) - 0x8000; /* Negative rotation: 0 - 0x7FFF */
}

uint16_t STM32_PLC_Encoder_Get(uint8_t i) {
	return encoder[i];
}

uint16_t compute_frequency(uint16_t t1, uint16_t t2){
	if(t1 < t2)
		return HAL_RCC_GetPCLK1Freq()/(t2 - t1);
	else if(t1 > t2 && t1 != counter_timer->Init.Period)
		return HAL_RCC_GetPCLK1Freq()/(counter_timer->Init.Period - t1 + t2);
	else
		return 0; /* t1 == t2 or t2 = 0 and t1 = period*/
}

void STM32_PLC_Input_Capture(uint8_t i) {
	T1[i] = T2[i];
	T2[i] = counter_timer->Instance->CNT;
	called_times[i]++; /* This is made for if T2 is a very old value and make sure that T1 is a previous value */
	if(called_times[i] >= 2) {
		input_capture[i] = compute_frequency(T1[i], T2[i]);
		called_times[i] = 0;
	}
}

uint16_t STM32_PLC_Input_Capture_Get(uint8_t i) {
	return input_capture[i];
}

void STM32_PLC_Input_Capture_Set(uint8_t i, uint16_t value){
	input_capture[i] = value;
}

/* Callback for Encoder and Input Capture */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef* htim){
	if (htim->Instance == TIM4) {
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
			STM32_PLC_Input_Capture(1);
		else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
			STM32_PLC_Input_Capture(0);
		else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1 || htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
			STM32_PLC_Encoder(htim, 0);
	} else if (htim->Instance == TIM19) {
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
			STM32_PLC_Input_Capture(2);
		else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1 || htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
			STM32_PLC_Encoder(htim, 1);
	}
}
Formax51
Inlägg: 75
Blev medlem: 30 april 2013, 18:56:19
Ort: Umeå

Re: Förslag på PWM, ADC, I/O och DAC IC kretsar med SPI?

Inlägg av Formax51 »

register TIMx_CNT är väl definierat som uint16_t .. men att göra en vanlig cast till int16_t...... value = (int16_t) TIMxCNT är väl förmodligen det enklaste.... då är ju register splittat i 2 hälften på minus å andra halvan på +..

att ta ut hastigheten .. borde väl vara enkel att få till i en vanlig timer interrupt.. räkna ut diff mellan samplingarna... och tidsenheten är ju känd när man satt upp interrupten.. sedan är det bara omvandla till önskad
enhet rpm, km/h m/s what ever..
Skriv svar