Project idea: to design a device based on an AVR microcontroller to control a ready-made GSM module (I chose the TC35 module from SIEMENS, but you can use any other if you are using RS232 serial communication). The device should be compact, minimally simple and reliable.
Sending a pre-stored message to the specified number should be performed after pressing the button. In total, there were 6 buttons to send to 6 different numbers. 3 LEDs (Ready, Send, Error) were selected to indicate the process, but later an alphanumeric LCD 16x2 was added (more for debugging the device than for normal use).
The whole thing was designed on a Pinboard II (Rev 2) board with a standard processor module on the ATmega16. On the finished device, the circuit was slightly different (and the microcontroller was used by the ATmega8). The program was written in AVR Studio 4.19. The project used various header files (#include) to switch between the Pinboard and the finished device.
')
General system layout:

For the controller, such a scarf was cut out:

There was a lot of time, so later I ordered the boards from the Chinese:

And when the hardware was finished, the programming process followed. Everything is written in C under AVR Studio 4.19. I post the complete project at the end of the article if anyone is interested in the complete code. But for now, let's talk about communication with the GSM module.
A complete list of AT commands is for each module in its documentation. But sending a message occurs by several teams.
Puts the module into text mode. I have not yet mastered the digital mode (until it was necessary). The module’s response was not used at the initial stages of the project. But then (when the descrambler of commands was written) served as a condition for the continuation of sending or a protocol error message. Go ahead:
: AT+CMGS=( )<enter> : > : Hello, GSM module!<ctrl-Z> : +CMGS: 62 OK
After typing the message, you need to send not Enter (0x0D) but CTRL-Z (0x1A). The module response after sending contains the sequence number of the message to be sent.
To send commands to the module and get answers, I used two
ring buffers with incoming and outgoing indices.
For better clarity of the code I will give the headers:
#define BUF_SIZE 128 #define BUF_MASK (BUF_SIZE-1) #define IN_BUF_SIZE 64 #define IN_BUF_MASK (IN_BUF_SIZE-1) volatile char buffer[BUF_SIZE]=""; volatile char inbuf[IN_BUF_SIZE]="$";
Writing strings or individual characters to the buffer was done using normal functions:
And sending is made through an interrupt handler:
Now, to send, you need to write the necessary command to the buffer (including the final \ n character), and then enable interrupts to empty the Send Register (UDR):
SendStr("AT+CMGF=1\n"); SendByte(CR);
While sending is in progress, you can send a message to the LCD or just wait (delay).
You cannot write to the buffer at this time. Experienced to find that the module does not have time to process a solid then commands. A stop occurs when the buffer is empty (incoming and outgoing indices are equal).
And so we send the message. Depending on the button pressed (in the main loop I scan the port), a message is sent:
while (1) { tmp = PINC; switch (tmp) { case 1: send_sms(0,NUM1); break; case 2: send_sms(0,NUM2); break; case 3: send_sms(0,NUM3); break;
I send the selected message number (I have 2 types) and a phone number to the sending function.
You can even send a command to the call with the same AT commands. It all depends on the required function.
Now about receiving commands from the module.
The module sends many commands. For example, OK, RING, ERROR ...
Sometimes it is necessary that when receiving a command the controller can recognize it and perform some kind of action. For example, received an incoming call. The module then sends to the controller:
RING RING RING
Depending on the module settings, it can also send the number of the caller. While there is no program, the controller will not be able to do anything with it (at best) or (at worst) it will do something wrong, or even completely freeze (cannot exit the interrupt).
Requirements for processing code:
1. The minimum amount of time to save the received commands. There should be no delays in the interrupt program. Then we will do anything with the resulting array.
2. Saving all received commands in one buffer. To separate the individual will use the $ symbol.
3. Recognize common commands in numeric codes. For example, OK will be 1, ERROR - 4, RING - 2.
I will cite the headings from the previous article with amendments:
#define BUF_SIZE 128
Writing a data reception interrupt handler:
Now we have all the commands written in the buffer. You can check the mess variable in your free time, and if it is not zero, run the command handler. In the project itself, commands for the LCD screen were added. Here I will miss them as useless.
void rx_check_in (void) { uint8_t count=0; com_detect = 0;
We pass the received symbols through the meat grinder. We do XOR operation. Thus we get a unique code (not sure about the uniqueness, but so far has not failed). R ^ I ^ N ^ G will give us 0x12. O ^ K will give 0x04. This code and the number of characters (in the command) are stored in the com_detect (global) and count variables. Now run the handler:
void code_com (uint8_t count) { switch (com_detect) { case (0x12): if (count == 4) com_detect = 2; break;
Recognized the team. I entered the number of characters for reliability in case the code in the long XOR command matches. Recognizable commands can be added. It is only necessary to calculate (or macro) the XOR code of the desired command and assign it a number.
Now in com_detect we got the command. Now the device can respond by SMS to the received call:
while (1) { if (mess != 0)
So you can handle different received commands.
The bottom line: the device can send a message to the phone and can respond to various commands from the GSM module.

Thanks for attention.
I post the
finished project for Pinboard II as an example.