Hallo zusammen, Ich muss 8 Timer von 2 Stm32f7 Nucleo Board im Encoder-Modus verwenden, um Encoder-Daten zu speichern. Aber ich muss die Timer synchronisieren. Dafür gibt es zwei Methoden: 1. Externe Clock 2. Master/Slave-Modus. Aber in diesen 2 Modi kann man keine Timer im Encoder-Modus verwenden. Kann jemand mir bitte helfen? Wie kann ich den Timer im Encoder-Modus synchronisieren?
Was soll "synchronisieren in encoder mode" bedeuten. Takt fuer die Timer kommt vom Encoder, da kannst Du nichts synchronisieren. Nur das Auslesen sollte moeglichst schnell hintereinander erfolgen, aber wenn Du die Timer zuegig hintereinander ausliest sehe ich da auch keine grosse Chance fuer Jitter. Evt waehrend der Auslese Interrupts deaktivieren...
Danke für deine Antwort. Ich habe 8 Timers von 2 Stm32F7 boards in encoder mode benutzt um die encoderinkremente zu lesen. Die 2 Boards und mein Programm funktionieren richtig, aber es gibt immer +/- 1ms Verzogerung zwischen Timers. (Z.B eine encoder zeigt die Werte 2000 in miliseconde 500 und die andere zeigt das in 501ms und die andere in 499ms) Ich muss die Timers synchronisieren. Timers kann man mit external clock oder in Master slave mode synchronisieren, aber so man kann nicht mehr Timers in encoder mode benutzen.
Wen ich das richtig verstehen : Sie haben 2 STM32 F7 µ-controller Jeden F7 µ ist verbunden mit ein motor-encoder mit A/B pulsen. Sie wollen jetzt das beide µ-controller das gleiche Ergebnis von pulsen zaehlen (es geht um nur ein motor) ?
Ja genau. Die beiden Boards zeigen richtig. Aber es gibt eine Verzögerung zwischen boards. ein Stm32 zeigt das Ergebnis 1 ms früher oder später im Vergleich mit dem anderen.
:
Bearbeitet durch User
Ich siehe 2 mogliche Fehlerquellen : 1. Die counter in beide F7 werden nicht auf den identische moment auf "0" gezetst. Hier soll ich ueber eine GPIO und ISR die counter auf 0 setzen. Damit ist eine synchronisierung in µs bereich machbar. 2. Wie werden die counter ausgelesen (usart, display)? Irgendwo muss die countervalue nach aussen kommen und interpretiert werden. Falls moglich auch hier mit ein GPIO und ISR die beide countervalues kopieren und den kopie nach aussen bringen.
Ich habe CubeMx benutz. Timer habe ich in Encoder Mode eingestellt. Dann habe ich die Channel A und B aktiviert: HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1); HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_2); Und die Encoderswerte ausgelesen mit: encoder_count = __HAL_TIM_GET_COUNTER(&htim1); Wie kann man Über eine GPIO und ISR die counter auf 0 setzen? Sorry für viele Fragen. Ich habe nicht zu viele Erfahrungen.
An jeden GPIO pin kann ein "Interrupt Service Routine" gekuppelt werden. Das ist ein Routine die unabhangig von den normale Ablauf ("loop") activiert werd wen ein GPIO-pin von Zustand wechselt. Das gleiche Signal muss naturlich an beide µ verbunden werden. Auch in cube kann das gemacht werden. Werden die Zaehler jetzt genullt bei booten von µ ? Steht en Motor dan, oder kann er schon drehen ? Wie werden den __HAL_TIM_GET_COUNTER(&htim1) sichtbar gemacht ? Wen das in der loop ist, sind die naturlich nicht synchronisiert. Beide loops laufen komplett unabhangig von ein ander.
Du meinst ich muss Die Werte nach einem Interrupt auslesen? Also ich muss encoder_count = __HAL_TIM_GET_COUNTER(&htim1); nach Interrupt machen? Dann wie kann ich Interrupts in jedem Mikro miteinander und mit anderem Mikro synchronisieren? Bei booten Encoderswerte wird null, deswegen ich denke ja die Zähler werden genullt. Motor ist unabhängig von diesem Projekt. Also es gibt ein Motor, der sich dreht. Der hat einen Inkrementalen Enkoder und ich muss die Inkremente vom Motor nur lesen. Das ist mein Programm:
1 | /* USER CODE BEGIN Header */
|
2 | /**
|
3 | ******************************************************************************
|
4 | * @file : main.c
|
5 | * @brief : Main program body
|
6 | ******************************************************************************
|
7 | * @attention
|
8 | *
|
9 | * <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
10 | * All rights reserved.</center></h2>
|
11 | *
|
12 | * This software component is licensed by ST under BSD 3-Clause license,
|
13 | * the "License"; You may not use this file except in compliance with the
|
14 | * License. You may obtain a copy of the License at:
|
15 | * opensource.org/licenses/BSD-3-Clause
|
16 | *
|
17 | ******************************************************************************
|
18 | */
|
19 | /* USER CODE END Header */
|
20 | /* Includes ------------------------------------------------------------------*/
|
21 | #include "main.h" |
22 | |
23 | /* Private includes ----------------------------------------------------------*/
|
24 | /* USER CODE BEGIN Includes */
|
25 | |
26 | /* USER CODE END Includes */
|
27 | |
28 | /* Private typedef -----------------------------------------------------------*/
|
29 | /* USER CODE BEGIN PTD */
|
30 | |
31 | /* USER CODE END PTD */
|
32 | |
33 | /* Private define ------------------------------------------------------------*/
|
34 | /* USER CODE BEGIN PD */
|
35 | /* USER CODE END PD */
|
36 | |
37 | /* Private macro -------------------------------------------------------------*/
|
38 | /* USER CODE BEGIN PM */
|
39 | |
40 | /* USER CODE END PM */
|
41 | |
42 | /* Private variables ---------------------------------------------------------*/
|
43 | |
44 | TIM_HandleTypeDef htim1; |
45 | |
46 | /* USER CODE BEGIN PV */
|
47 | int32_t encoder_count; |
48 | |
49 | |
50 | /* USER CODE END PV */
|
51 | |
52 | /* Private function prototypes -----------------------------------------------*/
|
53 | void SystemClock_Config(void); |
54 | static void MX_GPIO_Init(void); |
55 | static void MX_TIM1_Init(void); |
56 | /* USER CODE BEGIN PFP */
|
57 | |
58 | /* USER CODE END PFP */
|
59 | |
60 | /* Private user code ---------------------------------------------------------*/
|
61 | /* USER CODE BEGIN 0 */
|
62 | |
63 | /* USER CODE END 0 */
|
64 | |
65 | /**
|
66 | * @brief The application entry point.
|
67 | * @retval int
|
68 | */
|
69 | int main(void) |
70 | {
|
71 | /* USER CODE BEGIN 1 */
|
72 | |
73 | /* USER CODE END 1 */
|
74 | |
75 | /* MCU Configuration--------------------------------------------------------*/
|
76 | |
77 | /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
78 | HAL_Init(); |
79 | |
80 | /* USER CODE BEGIN Init */
|
81 | |
82 | /* USER CODE END Init */
|
83 | |
84 | /* Configure the system clock */
|
85 | SystemClock_Config(); |
86 | |
87 | /* USER CODE BEGIN SysInit */
|
88 | |
89 | /* USER CODE END SysInit */
|
90 | |
91 | /* Initialize all configured peripherals */
|
92 | MX_GPIO_Init(); |
93 | MX_TIM1_Init(); |
94 | /* USER CODE BEGIN 2 */
|
95 | |
96 | // HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_1);
|
97 | // HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_2);
|
98 | |
99 | HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1); |
100 | HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_2); |
101 | |
102 | |
103 | |
104 | |
105 | /* USER CODE END 2 */
|
106 | |
107 | /* Infinite loop */
|
108 | /* USER CODE BEGIN WHILE */
|
109 | while (1) |
110 | {
|
111 | /* USER CODE END WHILE */
|
112 | |
113 | /* USER CODE BEGIN 3 */
|
114 | |
115 | encoder_count = __HAL_TIM_GET_COUNTER(&htim1); |
116 | //encoder3 = __HAL_TIM_GET_COUNTER(&htim3);
|
117 | // encoder4 = __HAL_TIM_GET_COUNTER(&htim4);
|
118 | |
119 | }
|
120 | /* USER CODE END 3 */
|
121 | }
|
122 | |
123 | /**
|
124 | * @brief System Clock Configuration
|
125 | * @retval None
|
126 | */
|
127 | void SystemClock_Config(void) |
128 | {
|
129 | RCC_OscInitTypeDef RCC_OscInitStruct = {0}; |
130 | RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; |
131 | |
132 | /** Configure the main internal regulator output voltage
|
133 | */
|
134 | __HAL_RCC_PWR_CLK_ENABLE(); |
135 | __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); |
136 | /** Initializes the RCC Oscillators according to the specified parameters
|
137 | * in the RCC_OscInitTypeDef structure.
|
138 | */
|
139 | RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; |
140 | RCC_OscInitStruct.HSEState = RCC_HSE_ON; |
141 | RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; |
142 | RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; |
143 | RCC_OscInitStruct.PLL.PLLM = 8; |
144 | RCC_OscInitStruct.PLL.PLLN = 192; |
145 | RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; |
146 | RCC_OscInitStruct.PLL.PLLQ = 2; |
147 | if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) |
148 | {
|
149 | Error_Handler(); |
150 | }
|
151 | /** Activate the Over-Drive mode
|
152 | */
|
153 | if (HAL_PWREx_EnableOverDrive() != HAL_OK) |
154 | {
|
155 | Error_Handler(); |
156 | }
|
157 | /** Initializes the CPU, AHB and APB buses clocks
|
158 | */
|
159 | RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |
160 | |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; |
161 | RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; |
162 | RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; |
163 | RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; |
164 | RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; |
165 | |
166 | if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) |
167 | {
|
168 | Error_Handler(); |
169 | }
|
170 | }
|
171 | |
172 | /**
|
173 | * @brief TIM1 Initialization Function
|
174 | * @param None
|
175 | * @retval None
|
176 | */
|
177 | static void MX_TIM1_Init(void) |
178 | {
|
179 | |
180 | /* USER CODE BEGIN TIM1_Init 0 */
|
181 | |
182 | /* USER CODE END TIM1_Init 0 */
|
183 | |
184 | TIM_Encoder_InitTypeDef sConfig = {0}; |
185 | TIM_MasterConfigTypeDef sMasterConfig = {0}; |
186 | |
187 | /* USER CODE BEGIN TIM1_Init 1 */
|
188 | |
189 | /* USER CODE END TIM1_Init 1 */
|
190 | htim1.Instance = TIM1; |
191 | htim1.Init.Prescaler = 0; |
192 | htim1.Init.CounterMode = TIM_COUNTERMODE_UP; |
193 | htim1.Init.Period = 65535; |
194 | htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |
195 | htim1.Init.RepetitionCounter = 0; |
196 | htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; |
197 | sConfig.EncoderMode = TIM_ENCODERMODE_TI1; |
198 | sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; |
199 | sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; |
200 | sConfig.IC1Prescaler = TIM_ICPSC_DIV1; |
201 | sConfig.IC1Filter = 0; |
202 | sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; |
203 | sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; |
204 | sConfig.IC2Prescaler = TIM_ICPSC_DIV1; |
205 | sConfig.IC2Filter = 0; |
206 | if (HAL_TIM_Encoder_Init(&htim1, &sConfig) != HAL_OK) |
207 | {
|
208 | Error_Handler(); |
209 | }
|
210 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; |
211 | sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; |
212 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; |
213 | if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) |
214 | {
|
215 | Error_Handler(); |
216 | }
|
217 | /* USER CODE BEGIN TIM1_Init 2 */
|
218 | |
219 | /* USER CODE END TIM1_Init 2 */
|
220 | |
221 | }
|
222 | |
223 | /**
|
224 | * @brief GPIO Initialization Function
|
225 | * @param None
|
226 | * @retval None
|
227 | */
|
228 | static void MX_GPIO_Init(void) |
229 | {
|
230 | GPIO_InitTypeDef GPIO_InitStruct = {0}; |
231 | |
232 | /* GPIO Ports Clock Enable */
|
233 | __HAL_RCC_GPIOC_CLK_ENABLE(); |
234 | __HAL_RCC_GPIOH_CLK_ENABLE(); |
235 | __HAL_RCC_GPIOA_CLK_ENABLE(); |
236 | __HAL_RCC_GPIOB_CLK_ENABLE(); |
237 | __HAL_RCC_GPIOE_CLK_ENABLE(); |
238 | __HAL_RCC_GPIOD_CLK_ENABLE(); |
239 | __HAL_RCC_GPIOG_CLK_ENABLE(); |
240 | |
241 | /*Configure GPIO pin Output Level */
|
242 | HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin|LD2_Pin, GPIO_PIN_RESET); |
243 | |
244 | /*Configure GPIO pin Output Level */
|
245 | HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET); |
246 | |
247 | /*Configure GPIO pin : USER_Btn_Pin */
|
248 | GPIO_InitStruct.Pin = USER_Btn_Pin; |
249 | GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; |
250 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
251 | HAL_GPIO_Init(USER_Btn_GPIO_Port, &GPIO_InitStruct); |
252 | |
253 | /*Configure GPIO pins : RMII_MDC_Pin RMII_RXD0_Pin RMII_RXD1_Pin */
|
254 | GPIO_InitStruct.Pin = RMII_MDC_Pin|RMII_RXD0_Pin|RMII_RXD1_Pin; |
255 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
256 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
257 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
258 | GPIO_InitStruct.Alternate = GPIO_AF11_ETH; |
259 | HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); |
260 | |
261 | /*Configure GPIO pins : RMII_REF_CLK_Pin RMII_MDIO_Pin RMII_CRS_DV_Pin */
|
262 | GPIO_InitStruct.Pin = RMII_REF_CLK_Pin|RMII_MDIO_Pin|RMII_CRS_DV_Pin; |
263 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
264 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
265 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
266 | GPIO_InitStruct.Alternate = GPIO_AF11_ETH; |
267 | HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); |
268 | |
269 | /*Configure GPIO pins : LD1_Pin LD3_Pin LD2_Pin */
|
270 | GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin|LD2_Pin; |
271 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; |
272 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
273 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; |
274 | HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); |
275 | |
276 | /*Configure GPIO pin : RMII_TXD1_Pin */
|
277 | GPIO_InitStruct.Pin = RMII_TXD1_Pin; |
278 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
279 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
280 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
281 | GPIO_InitStruct.Alternate = GPIO_AF11_ETH; |
282 | HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); |
283 | |
284 | /*Configure GPIO pins : STLK_RX_Pin STLK_TX_Pin */
|
285 | GPIO_InitStruct.Pin = STLK_RX_Pin|STLK_TX_Pin; |
286 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
287 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
288 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
289 | GPIO_InitStruct.Alternate = GPIO_AF7_USART3; |
290 | HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); |
291 | |
292 | /*Configure GPIO pin : PG6 */
|
293 | GPIO_InitStruct.Pin = GPIO_PIN_6; |
294 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; |
295 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
296 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; |
297 | HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); |
298 | |
299 | /*Configure GPIO pin : USB_OverCurrent_Pin */
|
300 | GPIO_InitStruct.Pin = USB_OverCurrent_Pin; |
301 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; |
302 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
303 | HAL_GPIO_Init(USB_OverCurrent_GPIO_Port, &GPIO_InitStruct); |
304 | |
305 | /*Configure GPIO pins : USB_SOF_Pin USB_ID_Pin USB_DM_Pin USB_DP_Pin */
|
306 | GPIO_InitStruct.Pin = USB_SOF_Pin|USB_ID_Pin|USB_DM_Pin|USB_DP_Pin; |
307 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
308 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
309 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
310 | GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; |
311 | HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); |
312 | |
313 | /*Configure GPIO pin : USB_VBUS_Pin */
|
314 | GPIO_InitStruct.Pin = USB_VBUS_Pin; |
315 | GPIO_InitStruct.Mode = GPIO_MODE_INPUT; |
316 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
317 | HAL_GPIO_Init(USB_VBUS_GPIO_Port, &GPIO_InitStruct); |
318 | |
319 | /*Configure GPIO pins : RMII_TX_EN_Pin RMII_TXD0_Pin */
|
320 | GPIO_InitStruct.Pin = RMII_TX_EN_Pin|RMII_TXD0_Pin; |
321 | GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; |
322 | GPIO_InitStruct.Pull = GPIO_NOPULL; |
323 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; |
324 | GPIO_InitStruct.Alternate = GPIO_AF11_ETH; |
325 | HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); |
326 | |
327 | }
|
328 | |
329 | /* USER CODE BEGIN 4 */
|
330 | |
331 | /* USER CODE END 4 */
|
332 | |
333 | /**
|
334 | * @brief This function is executed in case of error occurrence.
|
335 | * @retval None
|
336 | */
|
337 | void Error_Handler(void) |
338 | {
|
339 | /* USER CODE BEGIN Error_Handler_Debug */
|
340 | /* User can add his own implementation to report the HAL error return state */
|
341 | __disable_irq(); |
342 | while (1) |
343 | {
|
344 | }
|
345 | /* USER CODE END Error_Handler_Debug */
|
346 | }
|
347 | |
348 | #ifdef USE_FULL_ASSERT
|
349 | /**
|
350 | * @brief Reports the name of the source file and the source line number
|
351 | * where the assert_param error has occurred.
|
352 | * @param file: pointer to the source file name
|
353 | * @param line: assert_param error line source number
|
354 | * @retval None
|
355 | */
|
356 | void assert_failed(uint8_t *file, uint32_t line) |
357 | {
|
358 | /* USER CODE BEGIN 6 */
|
359 | /* User can add his own implementation to report the file name and line number,
|
360 | ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
361 | /* USER CODE END 6 */
|
362 | }
|
363 | #endif /* USE_FULL_ASSERT */ |
364 | |
365 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
:
Bearbeitet durch User
Es ist mir immer noch unklar wie die Counter werte nach "aussen" gehen. In der main loop steht nur "encoder_count = __HAL_TIM_GET_COUNTER(&htim1);" Wie wissen sie dan das encouder_count verschiedene Werte haben in die 2 µ ?
Ich habe Cube Monitor benutzt die Daten zu speichern. Das gibt ein CSV. File. Darin kann man gut die Werte und Zeit sehen. im Foto die erste Spalte ist die Anzahl von Inkremente. 2. und 3. Spalte ist die Zeit für Encoder1 und Encoder2. Wie im Foto zu sehen ist Anzahl der Inkremente 88 ist für der erster Encoder in der Zeit 32ms but für zweiter Encoder in der 33ms. Manchmal das ist gleich manchmal das hat +-1ms Differenz.
:
Bearbeitet durch User
Eigenlich ist ihre problem das Cube Monitor diese 1ms nicht immer einhalt ? Da fehlen ab und zu eine Daten satz. Ich glaube nicht das dieses Verfahren auf millisecunden genau die Daten speichert ! Können sie nicht einfach mal die Motor stoppen, beide µ-controller resetten (counter =0), motor starten, motor wieder stoppen, und dan die erste und letzte Zaehlerstanden vergleichen ? Wen diese gleich sind, ist das encoder auswerten doch IO ?
Timer im Zählermode werden nicht genullt. Beim Nullen könnte ein gleichzeitiger Zählimpuls verloren gehen. Daher merkt man sich immer nur den vorherigen Zählerwert und bildet die Differenz zum aktuellen Zählerwert. Der Zählerwert ist quasi read-only. Will man an einer Referenzmarke den Zählerstand als Nullwert speichern, dann liest man ihn genau an der Referenzmarke aus. Die 1ms Unterschiede liegen an der Erstellung der CSV-Datei. Stehen die Encoder still, sollten die Differenzen zum Startwert wieder exakt gleich sein.
Danke für Ihre Antwort. Aber ich denke Stm32 kann nicht die schnelle Änderungen synchron zeigen. Ich habe den gleichen Encoder an 4 Timers angeschlossen. Theoretisch müssen die Werte immer gleich sein. Aber wie im Foto zu sehen ist bei der Änderung gibt es immer Unterschied. Aber wenn der Encoder in Standstill ist zeigen alle Timers richtig und gleiche Werte.
Ich vermute mal, das Debuggen erfolgt über USB und die 1ms Unterschied sind einfach die Pollingzeit des USB. Der Debugger kann daher nicht kleiner als 1ms auflösen.
Kann man irgendwie die Daten in Mikro speichern? So die Aufzeichnung der Daten ist unabhängig von USB.
Ja, das geht. Dan wird das problem verschoben nach "Diese Daten mussen ms genau auf beide µ gespeichert werden". Diese Zeitpunkt kann ueber eine GPIO "synchronisiert" werden ! Ein µ wird master, und gibt jeden secunde / milli secunde ein puls (GPIOpin High/Low)an die andere µ. Diese µ reagiert auf diesen puls mit eine interrupt. In die interrupt wird dan die zaehler wert gespeichert. Damit erreichen sie locker eine synchronisierung von 100 µsec.
1 | volatile int encodercounter[1000]; |
2 | Interrupt_GPIO{ |
3 | encodercounter[count]=zaehler; |
4 | count++; |
5 | if (count>998)count=0; |
6 | } |
Hallo Navid, vielleicht erklärst du Mal was genau du erreichen willst. Gehe einfach davon aus, dass die Encoder Counter in beiden Mikrocontrollern das gleiche anzeigen. Zumindest sofern beim einschalten der Controller der Encoder stillsteht. Das was du gerade hast, ist ein Ausleseproblem. Ist das in deinem Fall überhaupt ein wirkliches Problem? Was machst du später mit den Werten?
Hallo Gerald, Ich will die Encoderwerte messen. Ich habe 2 Stm32f7 Board benutzt. Mein Problem ist das, dass ich mit gleichem Encoder unterschiedliche Werte mit Mikro Boards auslese. Die Werte sind richtig aber ein Board zeigt die Werte mit +-1ms Verzögerung. Ich habe ein external Clock auch benutzt um Clock zu synchronisieren aber das Problem gibt es noch.
Navid M. schrieb: > Ich will die Encoderwerte messen. Das kann alles und nichts bedeuten. "Ich will Würfel messen" sagt genau so wenig aus.
Navid M. schrieb: > Ich will die Encoderwerte messen. Was willst Du denn messen? Um die Encoderauswertung zu überprüfen, fährt man eine Strecke hin und dann 10 Teilstrecken zurück. Danach muß man wieder beim gleichen Zählerstand angekommen sein, sonst stimmt was nicht.
Hallo Navid, das ist kein Problem einer nicht synchronen Clock. Das ist ein Problem wie du die Werte ausliest. Wenn du dir einmal Mühe bei deiner Antwort auf die Frage gibst, was du machen willst, sage ich dir, wie man das typischerweise richtig macht (dazu gehört beispielsweise kein Cube Monitor). Ich gebe dir dann sogar ein Beispiel dafür, wann und warum eine Clock synchronisiert sein muss.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.