SIM800 GSM Clock Function Interferes with SMS-Based Control Logic
The core issue revolves around the integration of a GSM clock function (send_clock
) into an SMS-controlled irrigation system using the STM32F103 microcontroller and SIM800 GSM module. The system operates in three modes: manual, semi-automatic, and automatic. The first two modes function correctly, but the automatic mode, which relies on the GSM clock to trigger actions at specific times, causes the entire system to fail. Specifically, when the send_clock
function is included in the code, the SMS-based control logic (e.g., turning an LED on/off) ceases to work. Removing the send_clock
function restores functionality.
The send_clock
function is designed to extract the current time from the SIM800 module and send it back via SMS. However, its inclusion disrupts the system’s ability to process incoming SMS commands. This suggests a conflict between the GSM clock functionality and the SMS handling logic, likely due to resource contention, timing issues, or improper handling of UART communication.
UART Resource Contention and Blocking Code Execution
The primary cause of the issue lies in the interaction between the UART peripheral and the blocking nature of the send_clock
function. The STM32F103 uses a single UART interface (USART1) to communicate with the SIM800 module. Both the SMS handling logic and the GSM clock functionality rely on this UART interface, leading to potential resource contention.
The send_clock
function employs blocking UART operations, such as HAL_UART_Receive
and HAL_UART_Transmit
, with long timeout values (e.g., 200,000 milliseconds). These blocking calls prevent the system from processing incoming SMS messages in a timely manner. Additionally, the function uses a wait_to_get
helper function, which continuously polls the UART for a specific character, further exacerbating the blocking behavior.
The UART receive buffer is also shared between the SMS handling logic and the send_clock
function. If the send_clock
function is actively reading from the UART, incoming SMS messages may be missed or corrupted, causing the system to fail to respond to commands.
Another contributing factor is the lack of proper synchronization between the GSM clock functionality and the SMS handling logic. The send_clock
function is called within the cmgr
function, which processes incoming SMS messages. This creates a tight coupling between the two functionalities, making it difficult to isolate and debug the issue.
Implementing Non-Blocking UART Communication and Task Prioritization
To resolve the issue, the system must be redesigned to handle UART communication in a non-blocking manner and prioritize tasks effectively. Below are the detailed troubleshooting steps and solutions:
Step 1: Refactor UART Communication to Use Interrupts or DMA
Replace the blocking UART operations in the send_clock
function with interrupt-driven or DMA-based communication. This allows the system to handle UART transactions asynchronously, freeing up the CPU to process other tasks, such as incoming SMS messages.
For example, modify the get_char
function to use UART receive interrupts:
volatile char received_char = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
received_char = huart->Instance->DR; // Read the received character
HAL_UART_Receive_IT(&huart1, (uint8_t*)&received_char, 1); // Re-enable interrupt
}
}
char get_char_non_blocking(void) {
while (received_char == 0); // Wait for a character to be received
char temp = received_char;
received_char = 0; // Reset the flag
return temp;
}
Step 2: Implement a State Machine for Task Management
Introduce a state machine to manage the different tasks (SMS handling, GSM clock, etc.) and ensure they do not interfere with each other. The state machine should prioritize critical tasks, such as processing incoming SMS messages, over less time-sensitive tasks, such as updating the GSM clock.
For example:
typedef enum {
STATE_IDLE,
STATE_PROCESS_SMS,
STATE_UPDATE_CLOCK,
STATE_SEND_SMS
} SystemState;
SystemState current_state = STATE_IDLE;
void System_Task_Handler(void) {
switch (current_state) {
case STATE_IDLE:
if (new_sms_received) {
current_state = STATE_PROCESS_SMS;
} else if (time_to_update_clock) {
current_state = STATE_UPDATE_CLOCK;
}
break;
case STATE_PROCESS_SMS:
Process_SMS();
current_state = STATE_IDLE;
break;
case STATE_UPDATE_CLOCK:
Update_Clock();
current_state = STATE_IDLE;
break;
default:
break;
}
}
Step 3: Use a Dedicated Buffer for UART Data
Allocate separate buffers for SMS handling and GSM clock functionality to prevent data corruption and ensure proper isolation. For example:
#define SMS_BUFFER_SIZE 128
#define CLOCK_BUFFER_SIZE 64
char sms_buffer[SMS_BUFFER_SIZE];
char clock_buffer[CLOCK_BUFFER_SIZE];
void Process_SMS(void) {
// Process data from sms_buffer
}
void Update_Clock(void) {
// Process data from clock_buffer
}
Step 4: Optimize Timing and Delays
Reduce or eliminate unnecessary delays in the send_clock
function and other parts of the code. Use timers to handle periodic tasks instead of relying on HAL_Delay
. For example, configure a hardware timer to trigger the GSM clock update at regular intervals:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) { // Assuming TIM2 is used for clock updates
time_to_update_clock = 1;
}
}
Step 5: Debug and Validate the System
Use debugging tools, such as breakpoints and logic analyzers, to monitor UART communication and verify that the system is functioning as expected. Pay particular attention to the timing of UART transactions and the state transitions in the task management system.
By implementing these solutions, the system can effectively handle both SMS-based control logic and GSM clock functionality without interference. The key is to ensure non-blocking UART communication, proper task prioritization, and robust resource management.