单片机
返回首页

基于STM32F103——SIM900A发送短信+串口打印

2022-09-22 来源:csdn

最近用STM32F103做一个智能门锁小玩意,密码输入错误次数多进行验证码解锁,这里我采用SIM900A来通过发送短信输入验证码进行解锁。就是简单的了解了一下在这里也单独的写写这个SIM900A的一写笔记。

基本介绍

在这里插入图片描述

。。。。。。还是直接进入主题吧


一:单独测试

SIM900A是可以AT指令操作的,所以一般我拿到这种模块就是先单独的测试一下这个模块是否正常。通过一个USB-TTL 和 SIM900A连接 进行调试。用我们的电脑串口助手测试即可。没必要上来就用单片机,现单独测试了先。没问题再转成代码也不迟。


1.准备工作

USB-TTL一个

在这里插入图片描述

还有杜邦线就不用说啦


2.接线

image.png

3.指令操作

打开你的串口助手

注意:建议使用卖家配套的串口助手

注意:建议使用卖家配套的串口助手

注意:建议使用卖家配套的串口助手


第一步:发送AT检测是否正常 (记得要回车换行再发送) 成功返回OK


AT


第二步:选择短消息格式(0:PDU模式 1:文本模式) (记得要回车换行再发送) 成功返回OK


AT+CMGF=1


第三步:选择TE字库集 (记得要回车换行再发送) 成功返回OK


AT+CSCS='UCS2'


第四步:保存SMS设置 (记得要回车换行再发送) 成功返回OK


AT+CSCA?


第五步:设置短消息文本模式参数 (记得要回车换行再发送) 成功返回OK


AT+CSMP=17,167,0,25


**第六步:设置接收短信方的电话号码(要转UNICON编码) (记得要回车换行再发送) 成功返回>**不知道咋转往下翻有一个代码是生成的。


AT+CMGS='你接收短信方的电话号码的UNICON编码'


第七步:发送要发送的内容(要转UNICON编码)(记得要回车换行再发送)成功返回>


'发送的内容的UNICON编码'


第八步:发送结束标志 16进制:0X1A 切换到16进制模式发送(不需要回车换行) 成功返回OK


1A


提示:

1.不出意外的话你设置接收短信的手机号码就能接收到你发送的短信内容


2.上面提到的为啥最好用卖家提供的串口助手呢 因为我一开始就没用卖家的,我用的其他,换了2个都是发送最后的1A 返回的error 而不是OK。后来用回他们提供的就成功了。


3.关于UNICON编码转换软件 一般卖家都会提供资料的 如下图

你没有也没关系 或者懒得找咱就自己写一个 我这里也有写 请忘下看 不过我这里是ASCII转Unicode 如果是中文你可以自己写一下 或者还是找软件转吧 哈哈哈哈

在这里插入图片描述

4.测试结果

在这里插入图片描述

二:关于Unicode编码

Unicode基本介绍

Unicode一般指统一码,也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。


1、编码方式

unicode是一种国际组织制定能容纳所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。


我们看图 我这里只是ASCII转… 凑合看吧

我们把ASCII字符串用当成双字节汉字转unicode码你发现1这个字符变成了0031

这31是不是你想到了什么,1的16进制不就是0X31吗?前面补2个0后面是它的16进制不就完事了么?

在这里插入图片描述

/**********************************************************************

描述: ASCII 转 unicode      比如 '1'  转成 '0031'

***********************************************************************/

void ASCII_TO_Unicode(char *ASCII,char *Unicode)

{

    int length;

    int i = 0;

    int j = 0;

memset(Unicode,'',sizeof(Unicode));

    length = strlen(ASCII);


    for(i=0;i    {

        Unicode[j++] = '0';

        Unicode[j++] = '0';


        Unicode[j++] = (ASCII[i] / 16) + 0x30;

        Unicode[j++] = (ASCII[i] % 16) + 0x30;

    }


}


比如我想把接收短信方的电话号码转一下

在这里插入图片描述

三:代码编写

有了刚才的测试,我们就可以转成代码来 用STM32F103来控制SIM900A发送短信了。


我这里不加入显示屏来了。直接用串口打印信息查看了。


用到资源:两个串口

串口1用于打印信息(充当显示屏)

串口2用于和SIM900A通信。


sim900a.c

#include 'sim900a.h'

#include

#include

#include

#include

#include 'usart.h'

#include 'delay.h'


uint8_t verification_code[7]; //存放验证码 


uint8_t sim900a_receive_data[128] = {0};

uint16_t sim900a_receive_count;


/**********************************************************************

描述:   SIM900A模块发送指令 函数

参数: *str:指令内容 ack:正常返回结果的数据 time:允许时间(1次代表 10ms)

返回: 0:指令得到正确回应 1: 指令没得到回应

***********************************************************************/

uint8_t sim900a_send_cmd(uint8_t *str,uint8_t *ack,uint16_t time)

{

memset(sim900a_receive_data,'',sizeof(sim900a_receive_data));

sim900a_receive_count = 0;

usart_sendString(USART2,(char *)str); //发送指令

if(ack == NULL) return 0;

//开启中断接收

OPEN_USART2_RECEIVE;

while(time--)

{

delay_ms(10);

//寻找要找的关键词 找到关中断接收 并且返回0

if(strstr((char *)sim900a_receive_data,(char *)ack) != NULL)

{

CLOSE_USART2_RECEIVE; //关闭中断接收

return 0;

}

}

CLOSE_USART2_RECEIVE; //关闭中断接收

return 1; //超时还没收到想要得到的关键词 关串口中断 并且返回1

}



/**********************************************************************

描述:   SIM900A模块发送指令 函数

参数: *str:指令内容 ack:正常返回结果的数据 time:允许时间(1次代表 10ms)

返回: 0:指令得到正确回应 1: 指令没得到回应

***********************************************************************/

uint8_t sim900a_send_end(uint8_t data,uint8_t *ack,uint16_t time)

{

sim900a_receive_count = 0;

memset(sim900a_receive_data,'',sizeof(sim900a_receive_data));


usart_sendByte(USART2,data); //发送结束指令

if(ack == NULL) return 0;

//开启中断接收

OPEN_USART2_RECEIVE;

while(time--)

{

delay_ms(10);

//寻找要找的关键词 找到关中断接收 并且返回0

if(strstr((char *)sim900a_receive_data,(char *)ack) != NULL)

{

CLOSE_USART2_RECEIVE; //关闭中断接收

return 0;

}

}

CLOSE_USART2_RECEIVE; //关闭中断接收

return 1; //超时还没收到想要得到的关键词 关串口中断 并且返回1

}




/**********************************************************************

描述:   随机生成验证码('0'~'9')

        产生字符 '0' ~ '9'  十进制也就是 48 ~ 57

***********************************************************************/

void generate_verification_code(char *data,uint8_t number)

{

    uint8_t i;

//    srand(time(NULL));


    for(i=0;i    {

        data[i] = 48 + (rand() % 10);

    }

}


/**********************************************************************

描述: ASCII 转 unicode      比如 '1'  转成 '0031'

***********************************************************************/

void ASCII_TO_Unicode(char *ASCII,char *Unicode)

{

    int length;

    int i = 0;

    int j = 0;

memset(Unicode,'',sizeof(Unicode));

    length = strlen(ASCII);


    for(i=0;i    {

        Unicode[j++] = '0';

        Unicode[j++] = '0';


        Unicode[j++] = (ASCII[i] / 16) + 0x30;

        Unicode[j++] = (ASCII[i] % 16) + 0x30;

    }


}


/**********************************************************************

描述: SIM900A 发送验证码 函数

返回: 0:成功 1:失败

***********************************************************************/

uint8_t sim900a_send_verification_code(void)

{

uint8_t ack; //存放状态

uint8_t err = 3; //设置可错误次数 

uint8_t send_count = 3; //发送次数 发送次数达到还是没成功则放弃发送

uint8_t sim900a_send_buffer[96] = {0};


SEND_AT:

strcpy((char *)sim900a_send_buffer,'AT+CMGS='');

//发送指令AT 检测是否返回OK 给300ms时间检测

ack = sim900a_send_cmd(SIM900A_SEND_AT,'OK',30);

if(ack)

{

if(err-- == 0)

{

printf('AT FAILrn');

return 1;

}

goto SEND_AT;

}

printf('AT OKrn');

err = 3;

//发送 短消息格式 指令 检测是否返回OK 给300ms时间检测

SELECT_SMS_FORMAT:

ack = sim900a_send_cmd(SIM900A_SELECT_SMS_FORMAT,'OK',30);

if(ack)

{

if(err-- == 0)

{

printf('SMS FORMAT FAILrn');

return 1;

}

goto SELECT_SMS_FORMAT;

}

printf('SMS FORMAT SUCCESSrn');

err = 3;




//发送 选择TE字库集 指令 检测是否返回OK 给300ms时间检测

SELECT_TE_FONT:

ack = sim900a_send_cmd(SIM900A_SELECT_TE_FONT,'OK',30);

if(ack)

{

if(err-- == 0)

{

printf('SELECT_TE_FONT FAILrn');

return 1;

}

goto SELECT_TE_FONT;

}

printf('SELECT_TE_FONT SUCCESSrn');

err = 3;




//发送 选择TE字库集 指令 不检测返回值

SAVE_SMS_SET:

ack = sim900a_send_cmd(SIM900A_SAVE_SMS_SET,NULL,0);

if(ack)

{

if(err-- == 0)

{

printf('SAVE_SMS_SET FAILrn');

return 1;

}

goto SAVE_SMS_SET;

}

printf('SAVE_SMS_SET SUCCESSrn');

err = 3;



//发送 设置短消息文本模式参数 指令 检测是否返回OK 给300ms时间检测

SET_SMS_TEST_MODE:

ack = sim900a_send_cmd(SIM900A_SET_SMS_TEST_MODE,'OK',30);

if(ack)

{

if(err-- == 0)

{

printf('SMS TEST MODE FAILrn');

return 1;

}

goto SET_SMS_TEST_MODE;

}

printf('SMS TEST MODE SUCCESSrn');

err = 3;



//让我们的设置接收短信方电话号码生成unicode编码

ASCII_TO_Unicode(PHONE_NUMBER,&sim900a_send_buffer[strlen(sim900a_send_buffer)]);

strcat((char *)sim900a_send_buffer,''rn');

printf('%srn',sim900a_send_buffer);

//发送 接收短信方电话号码 指令 检测是否返回OK 给1000ms时间检测

SELECT_PHONE_NUMBER:

ack = sim900a_send_cmd(sim900a_send_buffer,'>',100);

if(ack)

{

if(err-- == 0)

{

printf('SET PHONE NUMBER FAILrn');

return 1;

}

goto SELECT_PHONE_NUMBER;

}

printf('SET PHONE NUMBER SUCCESSrn');

err = 3;

//清空缓冲区 准备为发送验证码做准备

memset(sim900a_send_buffer,'',sizeof(sim900a_send_buffer));


//在这里开始就是开始发送内容了

//1-生成验证码

strcpy((char *)sim900a_send_buffer,'9A8C8BC17801003A'); //添加unicode码 '验证码:'

generate_verification_code((char *)verification_code,6);//生成验证码

printf('验证码生成结果:%srn',verification_code);

//2-将随机产生的6位验证码转Unicode编码 并且拼接一起

ASCII_TO_Unicode((char *)verification_code,&sim900a_send_buffer[strlen(sim900a_send_buffer)]);

strcat((char *)sim900a_send_buffer,'rn'); //加上回车换行 

printf('%srn',sim900a_send_buffer);

//3-发送数据

SEND_DATA:

ack = sim900a_send_cmd(sim900a_send_buffer,'>',300);

if(ack)

{

if(err-- == 0)

{

printf('SEND DATA FAILrn');

return 1;

}

goto SEND_DATA;

}

printf('SEND DATA SUCCESSrn');

//4-发送 0X1A 标志

ack = sim900a_send_end(0x1a,'OK',800);

if(ack)

{

if(send_count-- == 0) return 1;

memset(sim900a_send_buffer,'',sizeof(sim900a_send_buffer));

err = 3;

goto SEND_AT; //重发短信

}

printf('SEND MESSAGE SUCCESSrn');

return 0;

}


/**********************************************************************

描述: SIM900A 初始化 函数

返回: 0:成功 1:失败

***********************************************************************/

uint8_t sim900a_init(void)

{

uint8_t ack; //存放状态

uint8_t err; //设置可错误次数 


err = 3;

//发送指令AT 检测是否返回OK 给300ms时间检测

SEND_AT:

ack = sim900a_send_cmd(SIM900A_SEND_AT,'OK',30);

if(ack)

{

if(err-- == 0)

{

printf('AT FAILrn'); //ESP8266模块不存在

return 1;

}


goto SEND_AT;

}

printf('AT SUCCESSrn');

return 0;

}


sim900a.h

#ifndef __SIM900A_H

#define __SIM900A_H

#include 'stm32f10x.h'


/*用户必改 xxxxxxxxxxx 改成接收短信的电话号码*/

#define PHONE_NUMBER 'xxxxxxxxxxx'



#define SIM900A_SEND_AT 'ATrn'

//1.选择短消息格式 (0:PDU模式 1:文本模式)

#define SIM900A_SELECT_SMS_FORMAT 'AT+CMGF=1rn'

//2.选择TE字库集

#define SIM900A_SELECT_TE_FONT 'AT+CSCS='UCS2'rn'

//3.保存SMS设置

#define SIM900A_SAVE_SMS_SET 'AT+CSCA?rn'

//4.设置短消息文本模式参数

#define SIM900A_SET_SMS_TEST_MODE 'AT+CSMP=17,167,0,25rn'


extern uint8_t  sim900a_receive_data[128];

extern uint16_t  sim900a_receive_count;


extern uint8_t verification_code[7]; //存放验证码


uint8_t sim900a_send_cmd(uint8_t *str,uint8_t *ack,uint16_t time); //SIM900A模块发送字符串指令 函数

uint8_t sim900a_send_end(uint8_t data,uint8_t *ack,uint16_t time); //SIM900A模块发送单字节指令 函数

void generate_verification_code(char *data,uint8_t number); // 随机生成验证码('0'~'9')

void ASCII_TO_Unicode(char *ASCII,char *Unicode); // ASCII 转 unicode

uint8_t sim900a_init(void);

uint8_t sim900a_send_verification_code(void);

#endif



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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...rn');

}

while(sim900a_init());

printf('SIM900A Init Successrn');

if(sim900a_send_verification_code())

{

printf('发送短信失败rn');

}

else

{

printf('发送短信成功rn');

}

while(1);

}


项目演示

在这里插入图片描述

总结

问题1:一开始我采用电脑串口助手单独测试的时候,用了两个串口助手都到最后一步 发送 0x1A 时候返回error,以为是这个模块有问题,然后用回商家给的那个就成功了。。。。。所以还是建议用商家给的那个串口助手吧。。。。


问题2:如果发送失败,也有可能是你手机欠费了 哈哈哈哈哈哈哈。啊,我就是。擦。整我半天。

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 简洁的过零调功器电路设计与分析

  • 光控电路设计与分析

  • 开关电源的基本组成及工作原理

  • 比较常见的功率整流器和滤波电路

  • 基于M66T旋律发​​生器的电路图解析

  • 一个简单的红外耳机电路

    相关电子头条文章