最近用STM32F103做一個(gè)智能門鎖小玩意,密碼輸入錯(cuò)誤次數(shù)多進(jìn)行驗(yàn)證碼解鎖,這里我采用SIM900A來通過發(fā)送短信輸入驗(yàn)證碼進(jìn)行解鎖。就是簡單的了解了一下在這里也單獨(dú)的寫寫這個(gè)SIM900A的一寫筆記。
基本介紹
。。。。。。還是直接進(jìn)入主題吧
一:單獨(dú)測試
SIM900A是可以AT指令操作的,所以一般我拿到這種模塊就是先單獨(dú)的測試一下這個(gè)模塊是否正常。通過一個(gè)USB-TTL 和 SIM900A連接 進(jìn)行調(diào)試。用我們的電腦串口助手測試即可。沒必要上來就用單片機(jī),現(xiàn)單獨(dú)測試了先。沒問題再轉(zhuǎn)成代碼也不遲。
1.準(zhǔn)備工作
USB-TTL一個(gè)
還有杜邦線就不用說啦
2.接線
USB-TTL | SIM900A |
---|---|
5V | VCC5 |
GND | GND |
TX | 5VR |
RX | 5VT |
3.指令操作
打開你的串口助手
注意:建議使用賣家配套的串口助手
注意:建議使用賣家配套的串口助手
注意:建議使用賣家配套的串口助手
第一步:發(fā)送AT檢測是否正常 (記得要回車換行再發(fā)送) 成功返回OK
AT
第二步:選擇短消息格式(0:PDU模式 1:文本模式) (記得要回車換行再發(fā)送) 成功返回OK
AT+CMGF=1
第三步:選擇TE字庫集 (記得要回車換行再發(fā)送) 成功返回OK
AT+CSCS="UCS2"
第四步:保存SMS設(shè)置 (記得要回車換行再發(fā)送) 成功返回OK
AT+CSCA?
第五步:設(shè)置短消息文本模式參數(shù) (記得要回車換行再發(fā)送) 成功返回OK
AT+CSMP=17,167,0,25
**第六步:設(shè)置接收短信方的電話號碼(要轉(zhuǎn)UNICON編碼) (記得要回車換行再發(fā)送) 成功返回>**不知道咋轉(zhuǎn)往下翻有一個(gè)代碼是生成的。
AT+CMGS="你接收短信方的電話號碼的UNICON編碼"
第七步:發(fā)送要發(fā)送的內(nèi)容(要轉(zhuǎn)UNICON編碼)(記得要回車換行再發(fā)送)成功返回>
"發(fā)送的內(nèi)容的UNICON編碼"
第八步:發(fā)送結(jié)束標(biāo)志 16進(jìn)制:0X1A 切換到16進(jìn)制模式發(fā)送(不需要回車換行) 成功返回OK
1A
提示:
1.不出意外的話你設(shè)置接收短信的手機(jī)號碼就能接收到你發(fā)送的短信內(nèi)容
2.上面提到的為啥最好用賣家提供的串口助手呢 因?yàn)槲乙婚_始就沒用賣家的,我用的其他,換了2個(gè)都是發(fā)送最后的1A 返回的error 而不是OK。后來用回他們提供的就成功了。
3.關(guān)于UNICON編碼轉(zhuǎn)換軟件 一般賣家都會(huì)提供資料的 如下圖
你沒有也沒關(guān)系 或者懶得找咱就自己寫一個(gè) 我這里也有寫 請忘下看 不過我這里是ASCII轉(zhuǎn)Unicode 如果是中文你可以自己寫一下 或者還是找軟件轉(zhuǎn)吧 哈哈哈哈
4.測試結(jié)果
二:關(guān)于Unicode編碼
Unicode基本介紹
Unicode一般指統(tǒng)一碼,也叫萬國碼、單一碼,是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn),包括字符集、編碼方案等。Unicode是為了解決傳統(tǒng)的字符編碼方案的局限而產(chǎn)生的,它為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的二進(jìn)制編碼,以滿足跨語言、跨平臺進(jìn)行文本轉(zhuǎn)換、處理的要求。
1、編碼方式
unicode是一種國際組織制定能容納所有文字和符號的字符編碼方案。Unicode用數(shù)字0-0x10FFFF來映射這些字符,最多可以容納1114112個(gè)字符,或者說有1114112個(gè)碼位。碼位就是可以分配給字符的數(shù)字。UTF-8、UTF-16、UTF-32都是將數(shù)字轉(zhuǎn)換到程序數(shù)據(jù)的編碼方案。
我們看圖 我這里只是ASCII轉(zhuǎn)… 湊合看吧
我們把ASCII字符串用當(dāng)成雙字節(jié)漢字轉(zhuǎn)unicode碼你發(fā)現(xiàn)1這個(gè)字符變成了0031
這31是不是你想到了什么,1的16進(jìn)制不就是0X31嗎?前面補(bǔ)2個(gè)0后面是它的16進(jìn)制不就完事了么?
/**********************************************************************
描述: ASCII 轉(zhuǎn) unicode 比如 '1' 轉(zhuǎn)成 "0031"
***********************************************************************/
void ASCII_TO_Unicode(char *ASCII,char *Unicode)
{
int length;
int i = 0;
int j = 0;
memset(Unicode,'\0',sizeof(Unicode));
length = strlen(ASCII);
for(i=0;i<length;i++)
{
Unicode[j++] = '0';
Unicode[j++] = '0';
Unicode[j++] = (ASCII[i] / 16) + 0x30;
Unicode[j++] = (ASCII[i] % 16) + 0x30;
}
}
比如我想把接收短信方的電話號碼轉(zhuǎn)一下
三:代碼編寫
有了剛才的測試,我們就可以轉(zhuǎn)成代碼來 用STM32F103來控制SIM900A發(fā)送短信了。
我這里不加入顯示屏來了。直接用串口打印信息查看了。
用到資源:兩個(gè)串口
串口1用于打印信息(充當(dāng)顯示屏)
串口2用于和SIM900A通信。
sim900a.c
#include "sim900a.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usart.h"
#include "delay.h"
uint8_t verification_code[7]; //存放驗(yàn)證碼
uint8_t sim900a_receive_data[128] = {0};
uint16_t sim900a_receive_count;
/**********************************************************************
描述: SIM900A模塊發(fā)送指令 函數(shù)
參數(shù): *str:指令內(nèi)容 ack:正常返回結(jié)果的數(shù)據(jù) time:允許時(shí)間(1次代表 10ms)
返回: 0:指令得到正確回應(yīng) 1: 指令沒得到回應(yīng)
***********************************************************************/
uint8_t sim900a_send_cmd(uint8_t *str,uint8_t *ack,uint16_t time)
{
memset(sim900a_receive_data,'\0',sizeof(sim900a_receive_data));
sim900a_receive_count = 0;
usart_sendString(USART2,(char *)str); //發(fā)送指令
if(ack == NULL) return 0;
//開啟中斷接收
OPEN_USART2_RECEIVE;
while(time--)
{
delay_ms(10);
//尋找要找的關(guān)鍵詞 找到關(guān)中斷接收 并且返回0
if(strstr((char *)sim900a_receive_data,(char *)ack) != NULL)
{
CLOSE_USART2_RECEIVE; //關(guān)閉中斷接收
return 0;
}
}
CLOSE_USART2_RECEIVE; //關(guān)閉中斷接收
return 1; //超時(shí)還沒收到想要得到的關(guān)鍵詞 關(guān)串口中斷 并且返回1
}
/**********************************************************************
描述: SIM900A模塊發(fā)送指令 函數(shù)
參數(shù): *str:指令內(nèi)容 ack:正常返回結(jié)果的數(shù)據(jù) time:允許時(shí)間(1次代表 10ms)
返回: 0:指令得到正確回應(yīng) 1: 指令沒得到回應(yīng)
***********************************************************************/
uint8_t sim900a_send_end(uint8_t data,uint8_t *ack,uint16_t time)
{
sim900a_receive_count = 0;
memset(sim900a_receive_data,'\0',sizeof(sim900a_receive_data));
usart_sendByte(USART2,data); //發(fā)送結(jié)束指令
if(ack == NULL) return 0;
//開啟中斷接收
OPEN_USART2_RECEIVE;
while(time--)
{
delay_ms(10);
//尋找要找的關(guān)鍵詞 找到關(guān)中斷接收 并且返回0
if(strstr((char *)sim900a_receive_data,(char *)ack) != NULL)
{
CLOSE_USART2_RECEIVE; //關(guān)閉中斷接收
return 0;
}
}
CLOSE_USART2_RECEIVE; //關(guān)閉中斷接收
return 1; //超時(shí)還沒收到想要得到的關(guān)鍵詞 關(guān)串口中斷 并且返回1
}
/**********************************************************************
描述: 隨機(jī)生成驗(yàn)證碼('0'~'9')
產(chǎn)生字符 '0' ~ '9' 十進(jìn)制也就是 48 ~ 57
***********************************************************************/
void generate_verification_code(char *data,uint8_t number)
{
uint8_t i;
// srand(time(NULL));
for(i=0;i<number;i++)
{
data[i] = 48 + (rand() % 10);
}
}
/**********************************************************************
描述: ASCII 轉(zhuǎn) unicode 比如 '1' 轉(zhuǎn)成 "0031"
***********************************************************************/
void ASCII_TO_Unicode(char *ASCII,char *Unicode)
{
int length;
int i = 0;
int j = 0;
memset(Unicode,'\0',sizeof(Unicode));
length = strlen(ASCII);
for(i=0;i<length;i++)
{
Unicode[j++] = '0';
Unicode[j++] = '0';
Unicode[j++] = (ASCII[i] / 16) + 0x30;
Unicode[j++] = (ASCII[i] % 16) + 0x30;
}
}
/**********************************************************************
描述: SIM900A 發(fā)送驗(yàn)證碼 函數(shù)
返回: 0:成功 1:失敗
***********************************************************************/
uint8_t sim900a_send_verification_code(void)
{
uint8_t ack; //存放狀態(tài)
uint8_t err = 3; //設(shè)置可錯(cuò)誤次數(shù)
uint8_t send_count = 3; //發(fā)送次數(shù) 發(fā)送次數(shù)達(dá)到還是沒成功則放棄發(fā)送
uint8_t sim900a_send_buffer[96] = {0};
SEND_AT:
strcpy((char *)sim900a_send_buffer,"AT+CMGS=\"");
//發(fā)送指令A(yù)T 檢測是否返回OK 給300ms時(shí)間檢測
ack = sim900a_send_cmd(SIM900A_SEND_AT,"OK",30);
if(ack)
{
if(err-- == 0)
{
printf("AT FAIL\r\n");
return 1;
}
goto SEND_AT;
}
printf("AT OK\r\n");
err = 3;
//發(fā)送 短消息格式 指令 檢測是否返回OK 給300ms時(shí)間檢測
SELECT_SMS_FORMAT:
ack = sim900a_send_cmd(SIM900A_SELECT_SMS_FORMAT,"OK",30);
if(ack)
{
if(err-- == 0)
{
printf("SMS FORMAT FAIL\r\n");
return 1;
}
goto SELECT_SMS_FORMAT;
}
printf("SMS FORMAT SUCCESS\r\n");
err = 3;
//發(fā)送 選擇TE字庫集 指令 檢測是否返回OK 給300ms時(shí)間檢測
SELECT_TE_FONT:
ack = sim900a_send_cmd(SIM900A_SELECT_TE_FONT,"OK",30);
if(ack)
{
if(err-- == 0)
{
printf("SELECT_TE_FONT FAIL\r\n");
return 1;
}
goto SELECT_TE_FONT;
}
printf("SELECT_TE_FONT SUCCESS\r\n");
err = 3;
//發(fā)送 選擇TE字庫集 指令 不檢測返回值
SAVE_SMS_SET:
ack = sim900a_send_cmd(SIM900A_SAVE_SMS_SET,NULL,0);
if(ack)
{
if(err-- == 0)
{
printf("SAVE_SMS_SET FAIL\r\n");
return 1;
}
goto SAVE_SMS_SET;
}
printf("SAVE_SMS_SET SUCCESS\r\n");
err = 3;
//發(fā)送 設(shè)置短消息文本模式參數(shù) 指令 檢測是否返回OK 給300ms時(shí)間檢測
SET_SMS_TEST_MODE:
ack = sim900a_send_cmd(SIM900A_SET_SMS_TEST_MODE,"OK",30);
if(ack)
{
if(err-- == 0)
{
printf("SMS TEST MODE FAIL\r\n");
return 1;
}
goto SET_SMS_TEST_MODE;
}
printf("SMS TEST MODE SUCCESS\r\n");
err = 3;
//讓我們的設(shè)置接收短信方電話號碼生成unicode編碼
ASCII_TO_Unicode(PHONE_NUMBER,&sim900a_send_buffer[strlen(sim900a_send_buffer)]);
strcat((char *)sim900a_send_buffer,"\"\r\n");
printf("%s\r\n",sim900a_send_buffer);
//發(fā)送 接收短信方電話號碼 指令 檢測是否返回OK 給1000ms時(shí)間檢測
SELECT_PHONE_NUMBER:
ack = sim900a_send_cmd(sim900a_send_buffer,">",100);
if(ack)
{
if(err-- == 0)
{
printf("SET PHONE NUMBER FAIL\r\n");
return 1;
}
goto SELECT_PHONE_NUMBER;
}
printf("SET PHONE NUMBER SUCCESS\r\n");
err = 3;
//清空緩沖區(qū) 準(zhǔn)備為發(fā)送驗(yàn)證碼做準(zhǔn)備
memset(sim900a_send_buffer,'\0',sizeof(sim900a_send_buffer));
//在這里開始就是開始發(fā)送內(nèi)容了
//1-生成驗(yàn)證碼
strcpy((char *)sim900a_send_buffer,"9A8C8BC17801003A"); //添加unicode碼 "驗(yàn)證碼:"
generate_verification_code((char *)verification_code,6);//生成驗(yàn)證碼
printf("驗(yàn)證碼生成結(jié)果:%s\r\n",verification_code);
//2-將隨機(jī)產(chǎn)生的6位驗(yàn)證碼轉(zhuǎn)Unicode編碼 并且拼接一起
ASCII_TO_Unicode((char *)verification_code,&sim900a_send_buffer[strlen(sim900a_send_buffer)]);
strcat((char *)sim900a_send_buffer,"\r\n"); //加上回車換行
printf("%s\r\n",sim900a_send_buffer);
//3-發(fā)送數(shù)據(jù)
SEND_DATA:
ack = sim900a_send_cmd(sim900a_send_buffer,">",300);
if(ack)
{
if(err-- == 0)
{
printf("SEND DATA FAIL\r\n");
return 1;
}
goto SEND_DATA;
}
printf("SEND DATA SUCCESS\r\n");
//4-發(fā)送 0X1A 標(biāo)志
ack = sim900a_send_end(0x1a,"OK",800);
if(ack)
{
if(send_count-- == 0) return 1;
memset(sim900a_send_buffer,'\0',sizeof(sim900a_send_buffer));
err = 3;
goto SEND_AT; //重發(fā)短信
}
printf("SEND MESSAGE SUCCESS\r\n");
return 0;
}
/**********************************************************************
描述: SIM900A 初始化 函數(shù)
返回: 0:成功 1:失敗
***********************************************************************/
uint8_t sim900a_init(void)
{
uint8_t ack; //存放狀態(tài)
uint8_t err; //設(shè)置可錯(cuò)誤次數(shù)
err = 3;
//發(fā)送指令A(yù)T 檢測是否返回OK 給300ms時(shí)間檢測
SEND_AT:
ack = sim900a_send_cmd(SIM900A_SEND_AT,"OK",30);
if(ack)
{
if(err-- == 0)
{
printf("AT FAIL\r\n"); //ESP8266模塊不存在
return 1;
}
goto SEND_AT;
}
printf("AT SUCCESS\r\n");
return 0;
}
sim900a.h
#ifndef __SIM900A_H
#define __SIM900A_H
#include "stm32f10x.h"
/*用戶必改 xxxxxxxxxxx 改成接收短信的電話號碼*/
#define PHONE_NUMBER "xxxxxxxxxxx"
#define SIM900A_SEND_AT "AT\r\n"
//1.選擇短消息格式 (0:PDU模式 1:文本模式)
#define SIM900A_SELECT_SMS_FORMAT "AT+CMGF=1\r\n"
//2.選擇TE字庫集
#define SIM900A_SELECT_TE_FONT "AT+CSCS=\"UCS2\"\r\n"
//3.保存SMS設(shè)置
#define SIM900A_SAVE_SMS_SET "AT+CSCA?\r\n"
//4.設(shè)置短消息文本模式參數(shù)
#define SIM900A_SET_SMS_TEST_MODE "AT+CSMP=17,167,0,25\r\n"
extern uint8_t sim900a_receive_data[128];
extern uint16_t sim900a_receive_count;
extern uint8_t verification_code[7]; //存放驗(yàn)證碼
uint8_t sim900a_send_cmd(uint8_t *str,uint8_t *ack,uint16_t time); //SIM900A模塊發(fā)送字符串指令 函數(shù)
uint8_t sim900a_send_end(uint8_t data,uint8_t *ack,uint16_t time); //SIM900A模塊發(fā)送單字節(jié)指令 函數(shù)
void generate_verification_code(char *data,uint8_t number); // 隨機(jī)生成驗(yàn)證碼('0'~'9')
void ASCII_TO_Unicode(char *ASCII,char *Unicode); // ASCII 轉(zhuǎn) unicode
uint8_t sim900a_init(void);
uint8_t sim900a_send_verification_code(void);
#endif
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "sim900a.h"
/*
注意:先到 sim900a.h 填寫接收短信的電話號碼。
接線:
STM32F103 SIM900A
PA2 5VR
PA3 5VT
5V 5V
GND GND
*/
int main()
{
usart1_init(115200); //串口1初始化 用于打印信息
usart2_init(115200); //串口2初始化 用于和SIM900A模塊
do
{
printf("SIM900A Init...\r\n");
}
while(sim900a_init());
printf("SIM900A Init Success\r\n");
if(sim900a_send_verification_code())
{
printf("發(fā)送短信失敗\r\n");
}
else
{
printf("發(fā)送短信成功\r\n");
}
while(1);
}
項(xiàng)目演示
總結(jié)
問題1:一開始我采用電腦串口助手單獨(dú)測試的時(shí)候,用了兩個(gè)串口助手都到最后一步 發(fā)送 0x1A 時(shí)候返回error,以為是這個(gè)模塊有問題,然后用回商家給的那個(gè)就成功了。。。。。所以還是建議用商家給的那個(gè)串口助手吧。。。。
問題2:如果發(fā)送失敗,也有可能是你手機(jī)欠費(fèi)了 哈哈哈哈哈哈哈。啊,我就是。擦。整我半天。
如果我哪里寫的有問題,或者不好,請大家多多指教
#整個(gè)工程代碼。
printf("+meQ:844797079\n")
如果覺得這篇文章對你有用。歡迎大家點(diǎn)贊、評論哈哈文章來源:http://www.zghlxwxcb.cn/news/detail-411175.html
繼續(xù)加油!??!文章來源地址http://www.zghlxwxcb.cn/news/detail-411175.html
到了這里,關(guān)于基于STM32F103——SIM900A發(fā)送短信+串口打印的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!