CrazyEngineers
  • DIY GSM Phone with open source code

    ecoo

    Member

    Updated: Oct 26, 2024
    Views: 1.0K
    <removed> - [SIZE=-1]DIY mobile phone[/SIZE] [SIZE=-1]with full-format telephone keyboard powered from [/SIZE][SIZE=-1]AAA batteries. Open source code, free schematic.
    [/SIZE]
    0
    Replies
Howdy guest!
Dear guest, you must be logged-in to participate on CrazyEngineers. We would love to have you as a member of our community. Consider creating an account or login.
Replies
  • Kaustubh Katdare

    AdministratorJun 8, 2011

    Why not share it all here if it's open source? Removing the link.
    Are you sure? This action cannot be undone.
    Cancel
  • ecoo

    MemberJun 8, 2011

    The_Big_K
    Why not share it all here if it's open source?
    OK, you right, but I see "You may not post attachments" in my "Posting Permissions"
    Are you sure? This action cannot be undone.
    Cancel
  • Kaustubh Katdare

    AdministratorJun 8, 2011

    Yeah, you'll need 10+ posts for attachments. Share the code, through post, if you can 😀
    Are you sure? This action cannot be undone.
    Cancel
  • ecoo

    MemberJun 8, 2011

    The_Big_K
    Share the code, through post, if you can 😀
    OK. Code for IAR EW compilator, ATmega8 processor. Attention: tab = 3; russian comments.

    // ProtoPhone Mod01 Mammoth, DIY GSM Phone with open source code.
    // protoboardfab.com 
    // Программное обеспечение GSM-телефона ProtoPhone Mod01 Mammoth
    // Версия 0.1 от 23 мая 2011
    // Tab = 3 символа
    #include "iom8.h"                                // Определения внутренних регистров
    #include "inavr.h"                            // Intrinsic-функции
    #include "ctype.h"                            // Операции с символами
    #include "string.h"                            // Операции со строками
    
    #define bit(n)            (1 << (n))            // Определение операций с битами
    #define setbit(p,n)    (p|=bit(n))            // Установить бит
    #define clrbit(p,n)    (p&=~bit(n))        // Сбросить бит
    
    #define MASTERCLOCK 7372800                                            // Тактовая частота процессора в Гц
    #define delay_us(c) __delay_cycles(MASTERCLOCK/1000000*c)    // Микросекундная задержка. c max = 268435455
    #define delay_ms(c) __delay_cycles(MASTERCLOCK/1000*c)        // Миллисекундная задержка. c max = 268435
    
    // Порт B
    #define PWRKEY        1            // Включение GSM модуля
    #define ENA            2            // Включение питания GSM-модуля
    #define MOSI        3            // Линия MOSI SPI-интерфейса
    #define MISO        4            // Линия MISO SPI-интерфейса
    #define SCK            5            // Линия SCK SPI-интерфейса
    // Порт C
    #define COL2        0            // Колонка 2 опроса клавиатуры
    #define COL1        1            // Колонка 1 опроса клавиатуры
    #define BUZZ        2            // Вызывной динамик
    #define H_P            3            // Светодиод "Питание"
    #define H_C            4            // Светодиод "Звонок"
    #define H_SL        5            // Светодиод "Уровень сигнала"
    #define RST            6            // Сброс
    // Порт D
    #define TXD            0            // Выход UART GSM-модуля, вход UART микроконтроллера
    #define RXD            1            // Вход UART GSM-модуля, выход UART микроконтроллера
    #define ROW1        2            // Строка 1 опроса клавиатуры
    #define ROW2        3            // Строка 2 опроса клавиатуры
    #define COL3        4            // Колонка 3 опроса клавиатуры
    #define ROW5        5            // Строка 5 опроса клавиатуры
    #define ROW4        6            // Строка 4 опроса клавиатуры
    #define ROW3        7            // Строка 3 опроса клавиатуры
    #define ROWMASK    0xEC        // = 11101100b
    
    void PortInit(void)            // Активация портов ввода-вывода
    {
        DDRB = (1<<PWRKEY)|(1<<ENA);                                                    //    Порт B
        DDRC = (1<<COL2)|(1<<COL1)|(1<<BUZZ)|(1<<H_P)|(1<<H_C)|(1<<H_SL);    //    Порт C
        DDRD = (1<<RXD)|(1<<COL3);                                                        //    Порт D
        PORTD = (1<<ROW1)|(1<<ROW2)|(1<<ROW3)|(1<<ROW4)|(1<<ROW5);            // Включаем подтяжки у входов сканирования клавиатуры
    }// PortInit
    
    #define FRAMING_ERROR            (1<<FE)
    #define PARITY_ERROR                (1<<UPE)
    #define DATA_OVERRUN                (1<<DOR)
    #define DATA_REGISTER_EMPTY     (1<<UDRE)
    #define BAUD 115200                                // Скорость UART
    #define MYUBRR (MASTERCLOCK/16/BAUD-1)
    
    #define RXBUFLENGTH        100
    char RxBuf[RXBUFLENGTH];                        // Буфер, в который для дальнейшего анализа записываются данные от GSM-модема
    volatile unsigned char RxBufWrPoint = 0;
    
    #define NUMBUFLENGTH        30
    char NumBuf[NUMBUFLENGTH];                        // Буфер для набираемого номера
    volatile unsigned char NumBufWrPoint = 0;
    
    unsigned char GSMStatus = 0;    // Состояние GSM-модуля: 0 - выключен ; 1 - включен; 2 - исходящий звонок; 3 - входящий звонок; 4 - идет разговор по входящему звонку
    char GSMSigStrength = 0;        // Уровень сигнала
    
    void UARTinit(void)                                // Инициализация UART
    {    
        // Инициализация UART: 8 Data, 1 Stop; RX interrupt ON
       UCSRA = 0x00;
       UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);        // Приемник включен, передатчик включен, прерывание от приемника включено
        UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);        // Длина данных 8 бит
        UBRRH = (unsigned char) (MYUBRR>>8);            // Задаем скорость
        UBRRL = (unsigned char) (MYUBRR);
    }// UARTinit
    
    int putchar(int data)                            // Вывод байта в UART
    {
        while ( !( UCSRA & DATA_REGISTER_EMPTY));
        UDR = data;
        while ( !( UCSRA & DATA_REGISTER_EMPTY));
    
        return data;
    }//putchar
    
    void OutText (char *text)        // Вывод текста в UART
    {
        while (*text) putchar ( *text++ );
    }//OutText
    
    void OutDat (unsigned long int val, unsigned char len, unsigned char Const) // Вывод числа в UART
    {
        unsigned char Str[16];        // Максимальная длина числа (в печатаемом виде)
        unsigned char k = 0;
        
        for(k = 0; k < len; k++)    // Превращаем число в строку
        {
            *(Str + (len-k-1)) = (val%Const) + '0';
            
            if(*(Str+(len-k-1))>'9')
                *(Str+(len-k-1)) += 'A'-'0'-10;
            val /= Const;
        }
        
        Str[len] = 0;                    // Печатаем число
        k = 0;
        while(Str[k] != 0)
            putchar(Str[k++]);
    }//OutDat
    
    #pragma vector = USART_RXC_vect                // Прерывание по приходу байта в UART
    __interrupt void USART_RXC_Interrupt(void)
    {
        char InData = UDR;                            // Данные из UDR надо считать обязательно, даже если они нам не пригодятся
        if (InData > 20)                                // Отбрасываем служебные символы
        {
            RxBuf[RxBufWrPoint] = InData;            // Записываем пришедший байт в массив RxBuf
            RxBufWrPoint++;
        }
    }//USART_RXC_Interrupt
    
    void ClearRxBuf(void)                            // Очистка массива RxBuf
    {
        for (unsigned char ClearPoint = 0; ClearPoint < RXBUFLENGTH; RxBuf[ClearPoint++] = 0);
        RxBufWrPoint = 0;
    }//ClearRxBuf
    
    void ClearNumBuf(void)                            // Очистка массива RxBuf
    {
        for (unsigned char ClearPoint = 0; ClearPoint < NUMBUFLENGTH; NumBuf[ClearPoint++] = 0);
        NumBufWrPoint = 0;
    }//ClearNumBuf
    
    char KeyConvert(char RawKey)                    // Конвертирует значение, считанное с клавиатуры в читаемый вид
    {
        char ConvertedKey = 0;
        
        switch (RawKey)
        {
            case (0xE8): ConvertedKey = 'Y'; break;
            case (0xE4): ConvertedKey = '1'; break;
            case (0x6C): ConvertedKey = '4'; break;
            case (0xAC): ConvertedKey = '7'; break;
            case (0xCC): ConvertedKey = '*'; break;
            case (0xF7): ConvertedKey = 'S'; break;
            case (0xF3): ConvertedKey = '2'; break;
            case (0x7B): ConvertedKey = '5'; break;
            case (0xBB): ConvertedKey = '8'; break;
            case (0xDB): ConvertedKey = '0'; break;
            case (0x06): ConvertedKey = 'N'; break;
            case (0x02): ConvertedKey = '3'; break;
            case (0x8A): ConvertedKey = '6'; break;
            case (0xCA): ConvertedKey = '9'; break;
            case (0xEA): ConvertedKey = '#'; break;
            default: ConvertedKey = 0; break;
        }
        return ConvertedKey;
    }//KeyConvert
    
    char KeyScan(void)    // Сканирование клавиатуры. Выдает 0, если ни одна клавиша не нажата или код нажатой клавиши (от 1 до 15)
    {
        unsigned char PreKeyCode = 0;
        unsigned char KeyCode = 0;
        #define FIRST_DEBOUNCE_TIME    100
        #define DEBOUNCE_TIME    20
    
        clrbit(PORTC, COL1);    // Сканирование колонки 1
        setbit(PORTC, COL2);
        setbit(PORTD, COL3);
        delay_ms(DEBOUNCE_TIME);
        PreKeyCode = ROWMASK&PIND;
        delay_ms(DEBOUNCE_TIME);
        KeyCode = ROWMASK&PIND;
        if ((KeyCode == PreKeyCode)&&(KeyCode != ROWMASK))
            return KeyConvert(KeyCode);
    
        setbit(PORTC, COL1);    // Сканирование колонки 2
        clrbit(PORTC, COL2);
        setbit(PORTD, COL3);
        delay_ms(DEBOUNCE_TIME);
        PreKeyCode = ROWMASK&PIND;
        delay_ms(DEBOUNCE_TIME);
        KeyCode = ROWMASK&PIND;
        if ((KeyCode == PreKeyCode)&&(KeyCode != ROWMASK))
            return KeyConvert(KeyCode + 0x0F);
    
        setbit(PORTC, COL1);    // Сканирование колонки 3
        setbit(PORTC, COL2);
        clrbit(PORTD, COL3);
        delay_ms(DEBOUNCE_TIME);
        PreKeyCode = ROWMASK&PIND;
        delay_ms(DEBOUNCE_TIME);
        KeyCode = ROWMASK&PIND;
        if ((KeyCode == PreKeyCode)&&(KeyCode != ROWMASK))
            return KeyConvert(KeyCode + 0x1E);
    
        setbit(PORTC, COL1);    // Конец сканирования
        setbit(PORTC, COL2);
        setbit(PORTD, COL3);
        return 0;
    }//KeyScan
    
    void GSM_On(void)            // Включение GSM-модуля
    {
        setbit(PORTB, PWRKEY);
        delay_ms(3000);
        clrbit(PORTB, PWRKEY);
        delay_ms(8000);
        setbit(PORTB, PWRKEY);
        delay_ms(8000);    
    }//GSM_On
    
    void Beep(void)            // Короткий звуковой сигнал
    {
        setbit(PORTC, H_C);
        setbit(PORTC, BUZZ);
        delay_ms(10);
        if ((GSMStatus != 2) && (GSMStatus != 3))        // Если идет входящий или исходящий звонок, светодиод "Call" гасить не надо
            clrbit(PORTC, H_C);
        clrbit(PORTC, BUZZ);
        delay_ms(20);
    }//Beep
    
    void LongBeep(void)        // Звуковой сигнал подлиннее
    {
        setbit(PORTC, H_C);
        setbit(PORTC, BUZZ);
        delay_ms(15);
        if ((GSMStatus != 2) && (GSMStatus != 3))        // Если идет входящий или исходящий звонок, светодиод "Call" гасить не надо
            clrbit(PORTC, H_C);
        clrbit(PORTC, BUZZ);
        delay_ms(100);
    }//LongBeep
    
    void IncomingCallBeep(void)    // Длинный звуковой сигнал
    {
        setbit(PORTC, H_C);
        setbit(PORTC, BUZZ);
        delay_ms(100);
        if ((GSMStatus != 2) && (GSMStatus != 3))        // Если идет входящий или исходящий звонок, светодиод "Call" гасить не надо
            clrbit(PORTC, H_C);
        clrbit(PORTC, BUZZ);
        delay_ms(100);
    }//IncomingCallBeep
    
    unsigned int PowerFlashOrder = 0xAAAA;            // = 1010101010101010b
    unsigned int SignalLevelFlashOrder = 0x0000;
    
    void TimerInit(void)                        // Инициализация таймера
    {
        TCCR0 = (1<<CS00)|(1<<CS01);        // Тактирование от системного клока, с предделителем 1024 = ~30 мс @ 7 МГц
        TIMSK |= 1<<TOIE0;                    // Разрешить прерывания по достижению OCR0A
        TCNT0 = 0x00;
    }//TimerInit()
    
    unsigned int TimerCounter = 0;
    unsigned char SignalLevelObsolete = 0;
    
    #pragma vector = TIMER0_OVF_vect        // Прерывание по переполнению Timer0
    __interrupt void TIMER0_OVF_Interrupt(void)
    {
        TimerCounter++;
    
        if ((TimerCounter%0x80)==0)
        {
            PowerFlashOrder = (PowerFlashOrder<<1)|(PowerFlashOrder>>15);
            if(PowerFlashOrder&0x0001)    // Порядок свечения светодиода "Power"
                setbit(PORTC, H_P);
            else
                clrbit(PORTC, H_P);
    
            SignalLevelFlashOrder = (SignalLevelFlashOrder<<1)|(SignalLevelFlashOrder>>15);
            if(SignalLevelFlashOrder&0x0001)    // Порядок свечения светодиода "Signsl level"
                setbit(PORTC, H_SL);
            else
                clrbit(PORTC, H_SL);
            
            if ((TimerCounter%0x5000)==0)        // Пора вновь определить уровень сигнала
            {
                SignalLevelObsolete = 1;
            }
        }
    }//TIMER0_OVF_Interrupt
    
    int StrToInt (char* InputStr)                    // Процедура конвертирует строку в число типа int. Конвертируются только цифры
    {
        int ReturnValue = 0;
        unsigned char StrCount = 0;
    
        for (; StrCount <= strlen(InputStr); StrCount++)
            if (isdigit(InputStr[StrCount]))
                ReturnValue = 10*ReturnValue + (InputStr[StrCount] - 48);
    
        return ReturnValue;
    }//StrToInt
    
    void SignalLevelDefinition(void)
    {
        ClearRxBuf();                        // Перед AT+CSQ
        OutText("AT+CSQ\n\r");            // Запрос уровня сигнала сотовой сети
        delay_ms(300);
        OutText(RxBuf);OutText("\n\r");
        strtok(RxBuf, ",");                // Отсекаем bit error rate <ber>, который идет после запятой
        GSMSigStrength = StrToInt(RxBuf);
        if (GSMSigStrength >= 25)        // Нормальное значение
            GSMSigStrength = 5;
        else
        {
            GSMSigStrength /= 5;
            if (GSMSigStrength == 0) GSMSigStrength = 1;    // Чтобы моргнуть хотя бы раз и показать пользователю, что GSM-модуль видит сеть
        }
        if (GSMSigStrength == 99)                                //    Ненормальное значение, скорее всего, 99 - "Not known or not detectable"
            GSMSigStrength = 0;
    
        switch (GSMSigStrength)
        {// Порядок свечения светодиода "Signsl level"
            case 5:     SignalLevelFlashOrder = 0xAA80; break;    // = 1010101010000000b
            case 4:     SignalLevelFlashOrder = 0xAA00; break;    // = 1010101000000000b
            case 3:     SignalLevelFlashOrder = 0xA800; break;    // = 1010100000000000b
            case 2:     SignalLevelFlashOrder = 0xA000; break;    // = 1010000000000000b
            case 1:     SignalLevelFlashOrder = 0x8000; break;    // = 1000000000000000b        
            case 0:     SignalLevelFlashOrder = 0xAAAA; break;    // = 1010101010101010b
            default: break;
        }
    }//SignalLevelDefinition
    
    void main(void)
    {
          PortInit();                    // Активация портов ввода-вывода
        UARTinit();                    // Инициализация UART
        TimerInit();                // Инициализация таймера
        ClearRxBuf();
        
        asm("sei");                    // Разрешаем прерывания
    
        setbit(PORTC, H_P);        // Показываем, что питание подано
        delay_ms(300);
        Beep();
        delay_ms(300);
        Beep();
        delay_ms(1000);
    
        setbit(PORTB, ENA);        // Включаем питание GSM модуля
        delay_ms(1000);
        
        while (GSMStatus == 0)
        {
            GSM_On();                            // Включаем GSM модуль
            ClearRxBuf();
            OutText("AT+IPR=115200\n\r");    // Устанавливаем фиксированную скорость связи
            delay_ms(300);
            OutText("ATE0\n\r");                // Отключаем эхо в UART
            delay_ms(300);
            OutText("AT+CHFA=0\n\r");        // Выбираем аудиоканал
            delay_ms(300);
            OutText("AT+CLVL=90\n\r");        // Уровень усиления динамика
            delay_ms(300);
            OutText("AT+CMIC=0,7\n\r");    // Чувствительность микрофона
            delay_ms(300);
            
            if ((strstr(RxBuf, "OK") != NULL)    && (strstr(RxBuf, "ERROR") == NULL))    // Если GSM-модуль не выдал ошибки и выдал OK...
                GSMStatus = 1;
            ClearRxBuf();
        }
    
        LongBeep(); LongBeep(); LongBeep();
        SignalLevelDefinition();
        PowerFlashOrder = 0xFFFF;            // = 1111111111111111b, т. е. светодиод "Power" горит постоянно
        
        delay_ms(FIRST_DEBOUNCE_TIME);    // Для устаканивания переходных процессов после включения питания, могущих пролезть на входы сканирования клавиатуры
    
        char Key = 0;
        char OldKey = 0;
    
       while (1)
       {
            if (SignalLevelObsolete == 1)
            {
                SignalLevelDefinition();
                SignalLevelObsolete = 0;
            }
        
            if (strstr(RxBuf, "RING") != NULL)
            {
                IncomingCallBeep();
                IncomingCallBeep();
                IncomingCallBeep();
                IncomingCallBeep();
                GSMStatus = 3;
                setbit(PORTC, H_C);
            }
            
            if (strstr(RxBuf, "NO CARRIER") != NULL)
            {
                GSMStatus = 1;
                clrbit(PORTC, H_C);
            }
            
            if (strstr(RxBuf, "BUSY") != NULL)
            {
                GSMStatus = 1;
                clrbit(PORTC, H_C);
            }
            
            ClearRxBuf();
        
            OldKey = Key;
            Key = KeyScan();
            if ((Key != 0) && (Key != OldKey))    // Если что-то отсканировано и не повтор, моргнем лампочкой и вышлем код
            {
                if ((Key != 'Y') && (Key != 'S') && (Key != 'N') && (GSMStatus != 2) && (GSMStatus != 3) && (GSMStatus != 4))    // Нажата цифровая клавиша или * или # плюс во время разговора разблокированы только служебные клавиши "YES" и "NO"
                {
                    NumBuf[NumBufWrPoint] = Key;
                    NumBufWrPoint++;
                    Beep();
                }
            
                if (Key == 'N')                    //    Нажата клавиша "NO"
                {
                    ClearNumBuf();
                    OutText("ATH\n\r");            // ...то сбрасываем разговор
                    clrbit(PORTC, H_C);            // Гасим светодиод "Call"
                    GSMStatus = 1;
                    delay_ms(200);
                    LongBeep();
                    LongBeep();
                }
                
                if ((Key == 'Y')&&(GSMStatus == 1))    //    Нажата клавиша "YES"
                {
                    OutText("ATD"); OutText(NumBuf); OutText(";\n\r");    // Выходим на связь с набитым номером
                    ClearNumBuf();
                    delay_ms(200);
                    LongBeep();
                    LongBeep();
                    GSMStatus = 2;
                    setbit(PORTC, H_C);                    // Зажигаем светодиод "Call"
                }
                if ((Key == 'Y')&&(GSMStatus == 3))    //    Нажата клавиша "YES"
                {
                    OutText("ATA\n\r");
                    ClearNumBuf();
                    GSMStatus = 4;
                    delay_ms(200);
                    LongBeep();
                    LongBeep();
                    setbit(PORTC, H_C);                    // Зажигаем светодиод "Call"
                }
                
                if ((Key == 'S')&&(GSMStatus == 1))    //    Нажата клавиша "SOS"
                {
                    OutText("ATD89177985198;\n\r");    // Выходим на связь со службой технической поддержки protoboardfab.com
                    ClearNumBuf();
                    delay_ms(200);
                    LongBeep();
                    LongBeep();
                    GSMStatus = 2;
                    setbit(PORTC, H_C);                                            // Зажигаем светодиод "Call"
                }
            }
        }//while (1)
    }// main()
    
    Are you sure? This action cannot be undone.
    Cancel
  • ecoo

    MemberJun 8, 2011

    And a little video, if you allow.
    [video=youtube;hJw9nksJCG0]https://www.youtube.com/watch?v=hJw9nksJCG0[/video]
    Are you sure? This action cannot be undone.
    Cancel
Home Channels Search Login Register