vuoi
o PayPal
tutte le volte che vuoi
HAL_UART_Receive_IT(&huart2, (uint8_t *)&receivedChar, sizeof(receivedChar));
// Check if data has been received
if (correctlyReceivedData == 1)
{ correctlyReceivedData = 0; // Reset the receive flag
// Handle the received character
switch (receivedChar)
{
case '1': // Toggle the LED (GPIOA pin 5)
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_UART_Transmit_IT(&huart2, (uint8_t *)"LED Toggled\r\n", sizeof("LED Toggled\r\n"));
break;
case '2': // Send pushbutton status over UART
if (button_state == 0)
{ HAL_UART_Transmit_IT(&huart2, (uint8_t *)"PUSHBUTTON PRESSED\r\n", sizeof("PUSHBUTTON
PRESSED\r\n"));
}
else
{ HAL_UART_Transmit_IT(&huart2, (uint8_t *)"PUSHBUTTON RELEASED\r\n", sizeof("PUSHBUTTON
RELEASED\r\n"));
}
break;
case '3': // Show the menu again
HAL_UART_Transmit_IT(&huart2, (uint8_t *)welcomeMessage, sizeof(welcomeMessage));
break;
default: // Handle invalid options
HAL_UART_Transmit_IT(&huart2, (uint8_t *)"Invalid Option\r\n", sizeof("Invalid Option\r\n"));
break;
}
}
}
}
/* UART transmission complete callback */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{ correctlySentData = 1; // Set the transmission complete flag
}
/* UART reception complete callback */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{ correctlyReceivedData = 1; // Set the reception complete flag
}
NOTE: The two callback functions have a control role, verifying whether the transmission and
reception was successful, using the variables correctlySentData and correctlyReceivedData.
Finally, we proceeded on to the execution of the project using the "Serial_Interface_v2» program
to allow communication between the PC and the NucleoBoard. One thing to pay attention to is
that the Baud_rate of the two signals is equal, in order to have a correct transmission. Below
are the results obtained:
The program functions correctly: it toggles the pin if you send 1 from the PC, reads the
pushbutton status if you send 2 and rewrites the initial menu with 3.
4.2 & 4.3 Measure and simple analysis of the frequency and duty
cycle of an external square waveform
The objective of Exercise 4.2 is to measure the frequency and duty cycle of an external square
wave using the Input Capture functionality of the TIM3 timer. The calculated values must be
sent to the PC via serial communication. User interaction is done by sending commands: '1' to
obtain the frequency and '2' for the duty cycle.
Exercise 4.3 is an extension of the previous one. In addition to calculating and communicating
frequency and duty cycle values, the program must determine and store the maximum and
minimum frequency values detected since start-up. The user can request these values by
sending the commands '3' (maximum frequency) and '4' (minimum frequency).
Given the close correlation between the two exercises, they are treated in an integrated way,
with a particular focus on the additional functionalities required by exercise 4.3.
We started with the flowchart:
NOTE: The additions for exercise 4.3 are in orange.
Key variables such as PERIOD, HIGH_TIME, MAX_FREQ, MIN_FREQ, PSC, and flags
(FIRST_EDGE, SECOND_EDGE, THIRD_EDGE) are initialized in the flowchart for detecting
signal edges. The pin for Input Capture (PIN6) is configured in "alternate function" mode, and
the TIM3 timer is set to detect rising and falling edges, allowing duty cycle and frequency to be
calculated. Interrupts are enabled for TIM3 and UART.
During operation:
FIRST_EDGE: The first rising edge saves time in FIRST_TIME and triggers detection of the
• next edge.
SECOND_EDGE: The next falling edge records SECOND_TIME, from which HIGH_TIME
• is calculated.
THIRD_EDGE: The new rising edge saves THIRD_TIME and allows us to calculate the
• period (PERIOD), frequency and duty cycle, completing the cycle.
For Exercise 4.3, the minimum (MIN_FREQ) and maximum (MAX_FREQ) frequency values are
updated if the calculated frequency is lower or higher than the current values, respectively.
UART communication allows us to receive commands from the user and send a certain piece
of data depending on the command.
Then, we passed on to the configuration:
Configuration of the Timer with a frequency of 84MHz from the Clock Configuration,
• enabling of Timer 3 (CH1) and the relative Interrupt, configuration of the USART2 and the
relative Interrupt as in the last exercise;
Configuration of Timer 3 parameters: PSC = 27, to reduce the frequency of the Timer by
• always having an integer and avoiding too high a number of OVFs, polarity sensitive to
both edge;
Configuration of PINA6 in alternate function as it is connected to channel 1 of Timer 3,
• the one used
From the manual we used the following HAL functions:
HAL_TIM_IC_Start_IT(): starts the Input Capture mode on TIM3, channel 1, with
• interrupts enabled;
HAL_TIM_IC_CaptureCallback(): callback function triggered when an Input Capture
• event occurs. Reads and processes the captured timer value;
HAL_TIM_ReadCapturedValue(): reads the captured value from the specified timer
• channel;
HAL_UART_Receive_IT(): initiates non-blocking UART reception with interrupts;
• HAL_UART_Transmit_IT(): initiates non-blocking UART transmission with interrupts;
• HAL_UART_TxCpltCallback(): callback triggered when UART transmission is
• completed;
HAL_UART_RxCpltCallback(): callback triggered when UART reception is completed;
• HAL_TIM_PeriodElapsedCallback(): callback triggered when the timer counter
• overflows;
HAL_GPIO_ReadPin(): reads the state of the specified GPIO pin (high or low).
•
From here we wrote the code (in orange the part related to exercise 4.3):
#include "main.h"
#include <stdio.h>
#include "string.h"
volatile uint16_t firstEdgeTime = 0;
volatile uint16_t secondEdgeTime = 0;
volatile uint16_t thirdEdgeTime = 0;
volatile uint16_t highTime = 0;
volatile uint16_t period = 0;
volatile int ovf = 0;
volatile int dutyCycle = 0;
volatile int frequency = 0;
volatile int correctlySentData = 0;
volatile int correctlyReceivedData = 0;
char receivedChar;
volatile int first_edge = 0;
volatile int second_edge = 0;
volatile int third_edge = 0;
char freq_str[30];
char dc_str[30];
char maxFreq_str[30]; // For the maximum frequency
char minFreq_str[30]; // For the minimum frequency
volatile int maxFrequency = 0;
volatile int minFrequency = 201;
int main(void)
{ HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1); // Input Capture on PA6
while (1)
{ if (third_edge == 1)
{ snprintf(freq_str, sizeof(freq_str), "Frequency: %d Hz\r\n", frequency);
// Configure UART interface to receive a character
HAL_UART_Receive_IT(&huart2, (uint8_t *)&receivedChar, sizeof(receivedChar));
// Check if a character has been received
if (correctlyReceivedData == 1)
{ correctlyReceivedData = 0; // Reset the reception flag
// Handle the received character
switch (receivedChar)
{ case '1':
snprintf(freq_str, sizeof(freq_str), "Frequency: %d Hz\r\n", frequency);
// Transmit the frequency string via UART
HAL_UART_Transmit_IT(&huart2, (uint8_t *)freq_str, strlen(freq_str));
break;
case '2':
snprintf(dc_str, sizeof(dc_str), "Duty Cycle: %d%%\r\n", dutyCycle);
HAL_UART_Transmit_IT(&huart2, (uint8_t *)dc_str, strlen(dc_str));
break;
case '3': // Maximum frequency
snprintf(maxFreq_str, sizeof(maxFreq_str), "Max Frequency: %d Hz\r\n", maxFrequency);
HAL_UART_Transmit_IT(&huart2, (uint8_t *)maxFreq_str, strlen(maxFreq_str));
break;
case '4': // Minimum frequency
snprintf(minFreq_str, sizeof(minFreq_str), "Min Frequency: %d Hz\r\n", minFrequency);
HAL_UART_Transmit_IT(&huart2, (uint8_t *)minFreq_str, strlen(minFreq_str));
break;
default:
HAL_UART_Transmit_IT(&huart2, (uint8_t *)"Invalid Option\r\n", sizeof("Invalid Option\r\n"));
break;
}
}
}
}
}
/* Callback for Input Capture */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{ if (htim->Instance == TIM3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{ if (first_edge == 0)
{ if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 1)
{ firstEdgeTime = ovf * 65535 + HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
first_edge = 1;
third_edge = 0;
}
else
{ first_edge = 0;
}
}
else if (second_edge == 0)
{ if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 0)
{ secondEdgeTime = ovf * 65535 + HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
highTime = secondEdgeTime - firstEdgeTime; // High time
second_edge = 1;
}
}
else if (third_edge == 0)
{ if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == 1)
{ thirdEdgeTime = ovf * 65535 + HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
period = thirdEdgeTime - firstEdgeTime;
dutyCycle = (highTime * 100) / period; // Duty cycle in percentage
frequency = (84000000 / (27 + 1)) / period;
third_edge = 1;
// Update maximum and minimum frequency
if (frequency > maxFrequency)
{ maxFrequency = frequency;
}
if (frequency < minFrequency)
{ minFrequency = frequency;
}
}
}
}
}
/* UART Transmission Complete Callback */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{ correctlySentData = 1; // Set the transmission complete flag
}
/* UART Reception Complete Callback */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{ correctlyReceivedData = 1; // Set the reception complete flag
}
/* Timer Overflow Callback */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ ovf = ovf + 1;
}
NOTE: OVFs are taken into account in the calculation of EdgeTime to avoid incorrect
calculations in the presence of one or more OVFs between one front and another. Attention
should also be paid to the calculation of frequency such as:
= =
(+1)∙
84 = 27.
We finally moved on to the execution of the program, we used a signal generator to create a
square wave with a frequency of 70 Hz and a duty cycle of 60%. Through the
"Serial_Interface_v2" program, commands '1' and '2' were sent to request the microcontroller
to calculate and return the frequency and duty cycle. The values received were correct,
confirming the good functioning of the system.
Next, we changed the frequency to 100 Hz to test MAX_FREQ and MIN_FREQ values. By sending
commands '3' and '4', the system correctly reported the maximum and minim