我在做一个基于STM32的驱动GPRS模块(TC35)给手机发短信,用AT指令测试连通性,即通过STM32串口发"AT\r“ 给GPRS模块,我用的是原子哥的MINI STM32开发板,由于开发板没有 RS323串口,所以我就用杜邦线连接STM32的串口2,即PA2、PA3,现在遇到的问题是发送完后,接收的并不是OK,可以推断没有连通,之后的信息发送自然做不了。我不知道程序哪里有问题,我已经仔细学习了STM32的串口、数据接收和发送,有没有那位大哥做过,帮我看看程序到底哪里出错了,先谢谢了,急,在线等!
下面是主要代码:
usart.c
#ifdef EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[64]; //接收缓冲,最大64个字节.
//接收状态
//bit7,接收完成标志
//bit6,接收到0x0d
//bit5~0,接收到的有效字节数目
u8 USART_RX_STA=0; //接收状态标记
void USART1_IRQHandler(void)
{
u8 res;
if(USART1->SR&(1<<5))//接收到数据
{
res=USART1->DR;
if((USART_RX_STA&0x80)==0)//接收未完成
{
if(USART_RX_STA&0x40)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x80; //接收完成了
}else //还没收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x40;
else
{
USART_RX_BUF[USART_RX_STA&0X3F]=res;
USART_RX_STA++;
if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
#endif
#ifdef EN_USART2_RX //如果使能了接收
u8 USART2_RX_BUF[64]; //接收缓冲,最大64个字节.
u8 USART2_RX_STA=0; //接收状态标记
void USART2_IRQHandler(void)
{ u8 res2;
if(USART2->SR&(1<<5))//接收到数据
{
res2=USART2->DR;
USART2_RX_BUF[USART2_RX_STA]=res2;
USART2_RX_STA++;
if(USART2_RX_STA>63)USART2_RX_STA=0;//接收数据错误,重新开始接收
}
}
#endif
//初始化IO 串口1
//pclk2CLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB2ENR|=1<<14; //使能串口时钟
GPIOA->CRH&=0XFFFFF00F;
GPIOA->CRH|=0X000008B0;//IO状态设置
RCC->APB2RSTR|=1<<14; //复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位
//波特率设置
USART1->BRR=mantissa; // 波特率设置
USART1->CR1|=0X200C; //1位停止,无校验位.
#ifdef EN_USART1_RX //如果使能了接收
//使能接收中断
USART1->CR1|=1<<8; //PE中断使能
USART1->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
void uart2_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB1ENR|=1<<17; //使能串口时钟
GPIOA->CRL&=0XFFFF00FF;
GPIOA->CRL|=0X00008B00;//IO状态设置
RCC->APB1RSTR|=1<<17; //复位串口1
RCC->APB1RSTR&=~(1<<17);//停止复位
//波特率设置
USART2->BRR=mantissa; // 波特率设置
USART2->CR1|=0X200C; //1位停止,无校验位.
#ifdef EN_USART2_RX //如果使能了接收
//使能接收中断
USART2->CR1|=1<<8; //PE中断使能
USART2->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART2_IRQChannel,2);//组2,最低优先级
#endif
}
void SendASC(u8 d)//发送一个字节
{
USART2->DR=d;
while((USART2->SR&0X40)==0);//等待发送结束
}
void SendString(u8 *str) //发送字符串
{
while(*str)
{
SendASC(*str) ;
str++;
}
}
gprs.c
u8 PhoneNum[15]="+8615175655278"; //手机号码
const u8 *MsContent="Temperature exceeds bid !"; //短信内容
//查找字符串,在s中查找t
//返 回 值: 1(t在s中的位置)成功 0失败
u8 LookFor_Str(u8 *s, u8 *t)
{
u8 *s_temp;
u8 *m_temp;
u8 *t_temp;
if (s == 0 ||t == 0)
return 0;
for (s_temp = s; *s_temp != '\0'; s_temp++)
{
m_temp = s_temp;
for (t_temp = t; *t_temp == *m_temp; t_temp++, m_temp++);
if (*t_temp == '\0')
return 1;
}
return 0;
}
//发送"AT"联机指令,测试是否连接正确
void Send_AT(void)
{
u8 p;
u8 i=10;
while(i--) //测试10次,在某一次成功就退出
{
USART2_RX_STA=0; //buffer指针清0
SendString("AT\r"); //发送AT回车
//delay_ms(100); //等待接受数据完成
while(USART2_RX_STA==0);
//printf("n=%d\n",USART2_RX_STA);
delay_ms(300);
printf("b=%s\n",USART2_RX_BUF);
p=LookFor_Str(USART2_RX_BUF,"OK"); //接收到的数据存在 USART2_RX_BUF
if(p!=0) //接收到"OK"
{
printf("GSM 模块正常!\n");
delay_ms(1000);
break;
}
printf("没检测到GSM 模块!\n");
delay_ms(500);
}
}
//设置短信模式 1:text模式 0DU模式
//串口发送数组命令到TC35,AT+CMGF=1
void Set_Mode(u8 mode)
{
u8 p,i=10;
while(i--) //测试10次,在某一次成功就退出
{
USART2_RX_STA=0; //buffer指针清0
if(mode) SendString("AT+CMGF=1\r"); //设置短消息模式 1 TEXT
else SendString("AT+CMGF=0\r"); //设置短消息模式 PDU模式
//delay_ms(300); //等待接受数据完成
while(flag==0);
flag=0;
delay_ms(300);
p=LookFor_Str(USART2_RX_BUF,"OK"); //接收到的数据存在RsBuf
if(p!=0) //接收到"OK"
{
printf("短信模式:text");
delay_ms(1000);
break;
}
printf("短信模式设置失败!");
delay_ms(500);
}
}
//发送号码
void Send_PhoneNum(u8 *str)
{
u8 i=0;
while(*str)
{
SendASC(*str) ;
str++;
i++;
if(i==14) break; //只发送14个
}
}
//发送TEXT短信 AT+CMGS="+8615175655278"
//*dialnum 目的号码 *text短信内容
//返回:1 发送成功 0 发送失败
u8 TransmitText(u8 *dialnum,u8 *text)
{
u8 i=10;
u8 p;
while(i--)
{
USART2_RX_STA=0; //buffer指针清0
SendString("AT+CMGS="); //信息发送指令 AT+CMGS="+8613760602242"
SendASC('"');
Send_PhoneNum(dialnum); //号码
SendASC('"');
SendASC('\r'); //回车
while(flag==0);
flag=0;
delay_ms(300);
p=LookFor_Str(USART2_RX_BUF,">"); //">"
if(p!=0) //如果接受到 > 发送text
{
USART2_RX_STA=0; //清空接收缓冲区
SendString(text); //发送短信内容
SendString("\x1a\r"); //'\x1a'结束符(相当CTRL+Z) '\r'回车符
while(flag==0);
flag=0;
delay_ms(5000); //这里要延时足够长时间,否则会读取错误
p=LookFor_Str(USART2_RX_BUF,"OK"); //查找OK
if(p!=0) //发送成功
{
printf("发送成功 ^_^");
return 1;
}
else
{
printf("发送失败");
delay_ms(1000);
printf("正在重发");
}
}
}
printf("多次重发失败");
return 0;
}
//完整的短信发送函数
//dialnum:手机号码 text:短信内容
void Send_Message(u8 *dialnum,u8 *text)
{
Send_AT(); //发送AT
Set_Mode(1); //设置短信模式:text
TransmitText(dialnum,text); //设置
}
main.c
#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "gprs.h"
//Mini STM32开发板范例代码3
//串口实验
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口初始化为9600
uart2_init(72,9600);
LED_Init(); //初始化与LED连接的硬件接口
while(1)
{
Send_AT();
LED0=!LED0;//闪烁LED,提示系统正在运行.
}
主函数只是发送"AT"联机指令,测试是否连接正确,老出错,我想只要这个调通了,其他就可以照着写了。程序是学习原子开发板例程写的,都是直接操作寄存器。
关键函数我已经标红了,希望懂的的大侠帮我看看,串口数据接收和发送那出问题了,谢谢!
|