硬件平台:stm32f10xZET6
开发环境:keil MDK uVision v4.10
开发语言:C、ST_lib_3.5固件库
【串口通信】
}
// usart.c
#include "usart.h"
extern sdstring atcmd_recv_buff;
/**
* @ USART1 GPIO 配置,工作模式配置。115200 8-N-1
*/
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 配置 USART1 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 GPIO 配置 */
/* 配置 USART1 Tx (PA9) 为复用推挽输出模式,速度50MHZ */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置 USART1 Rx (PA10) 为浮空输入模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART1 工作参数配置:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure); // 写入初始化信息
USART_Cmd(USART1, ENABLE); /* 使能 USART1 */
}
/**
* @ USART1 NVIC 中断配置
*/
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置 NVIC 优先组0 (4位的16级优先级可选 - 0~15) */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* 使能USART1中断 */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 1~15
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
// usart1中断处理函数在 stm32f10x_it.c line:156
/**
* @ USART2 GPIO 配置,工作模式配置。115200 8-N-1
*/
void USART2_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
sds_clean(&atcmd_recv_buff); // 接收前初始化清理一次公共缓冲区
/* 使能 USART2 时钟 */
RCC_APB1PeriphClockCmd (RCC_APB1Periph_USART2 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* 配置 USART2 Tx (PA2) 为复用推挽输出模式,速度50MHz */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置 USART2 Rx (PA3) 为输入浮空模式 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART2 工作参数配置:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure); // 写入初始化信息
/* 使能串口2接收中断 */
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE); /* 使能 USART2 */
}
/* USART1 - 发送字符、接收字符 (轮询也用于printf重定向) */
int SendChar (int ch) { /* 发送字符 8bit/byte */
USART_SendData(USART1, (unsigned char) ch); /* 将1字节数据发往串口寄存器 */
// while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); /* 轮询等待传输结束 */
while (!(USART1->SR & USART_FLAG_TXE));
return ch;
}
int GetData (void) { /* 读取字符 8bit/byte */
while (!(USART1->SR & USART_FLAG_RXNE));
return (USART_ReceiveData(USART1));
}
/* USART2 - 发送字符、接收字符 (轮询也用于printf重定向) */
int SendCharSerail2 (int ch) { /* 发送字符 8bit/byte */
USART_SendData(USART2, (unsigned char) ch);
while (!(USART2->SR & USART_FLAG_TXE));
return (ch);
}
int GetDataSerial2 (void) { /* 读取字符 8bit/byte */
while (!(USART2->SR & USART_FLAG_RXNE));
return (USART_ReceiveData(USART2));
}
/*********************************************END OF FILE**********************/
// retarget.c
#include
#include
#include "usart.h"
/*
* 函数名: fputc
* 描述 : 重定向 c 库函数 printf 到 USART1
*/
int fputc(int ch, FILE *f)
{
#if 1 // 1-USART1 : 0-USART2
USART_SendData(USART1, (unsigned char) ch); // 将1字节数据发往串口寄存器,printf测试usart2回显
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // 轮询是否发送完成,标志位TC
#else
USART_SendData(USART2, (unsigned char) ch); // 将1字节数据发往串口寄存器
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); // 轮询是否发送完成,标志位TC
#endif
return (ch);
}
// 从USART中的数据
int fgetc(FILE *f)
{
#if 1
return (SendChar (GetData ()));
#else
return (SendCharSerail2 (GetData ()));
#endif
}
// at_cmd.c
#include "at_cmd.h"
sdstring atcmd_recv_buff; //atcmd_recv_buff.buff 全局缓冲区,存放返回数据
// 逐个发送AT命令集
void send_all_at_cmd (void)
{
char *p_res = NULL;
char *p_str = "hello";
send_at_cmd (AT_AT);
p_res = receive_data ();
print_log_info ("recv data");
// if "OK"/0
if (! strstr (p_res, "OK")) {
return ;
}
send_at_cmd (AT_CGATT);
p_res = receive_data ();
print_log_info ("recv data");
// if "OK"/0
send_at_cmd (AT_CGATT_1);
p_res = receive_data ();
print_log_info ("recv data");
// if "OK"/0
send_at_cmd (AT_CON_TCP);
p_res = receive_data ();
print_log_info ("recv data");
// if "CONNECT OK"
send_at_cmd (AT_CIPSEND);
p_res = receive_data ();
print_log_info ("recv data");
// if ">"
send_at_cmd (p_str);
p_res = receive_data ();
print_log_info ("recv data");
// if "HTTP/1.1 400 Bad Request"
#if 0
send_at_cmd (AT_CIPCLOSE); // 关闭TCP连接命令
p_res = receive_data ();
print_log_info ("recv cmd");
// if "OK"/0
#endif
}
// 发送单个AT命令,打印提示日志
void send_at_cmd (char *p_cmd)
{
//int i = 0;
#if 1
send_USART2 (p_cmd, strlen (p_cmd));
send_USART2 (AT_CONFIRM, strlen (AT_CONFIRM)); // \r\n
strcpy (atcmd_recv_buff.buff, p_cmd);
print_log_info ("send cmd");
#else
// 发送什么指令-回显到屏幕(USART1重定向了printf)单向传输测试
printf ("\r\n%s", p_cmd);
#endif
}
// 接收发送命令后GPRS通过串口端自动回复的数据
char* receive_data (void)
{
int i;
memset (atcmd_recv_buff.buff, 0, sizeof (atcmd_recv_buff.buff));
#if 1
// 轮询读取USART2接收寄存器的信息到atcmd_recv_buff.buff[]
do {
while(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);
atcmd_recv_buff.buff[i] = USART2->DR;
// 如果在USART2的接收寄存器中接收到 \n 字符,作为结束标志
if(atcmd_recv_buff.buff[i] == '\n') {
break;
}
i++;
} while(1);
return (atcmd_recv_buff.buff);
#else // used to test... 测试返回数据
memset (atcmd_recv_buff.buff, 0, sizeof (atcmd_recv_buff.buff));
strcpy (atcmd_recv_buff.buff, "OK\r\n");
return (atcmd_recv_buff.buff);
#endif
}
// 往连接GPRS串口的USART2串口中发送字符串数据
void send_USART2 (char *pdata, int len)
{
int index = 0;
for(index = 0; index < len; index++)
{
SendCharSerail2(pdata[index]);
}
}
/*
// 测试IP:123.58.34.245 测试端口:80
void send_connect_cmd (char *ip,int port)
{
char buf[40]={0};
send_at_cmd (AT_CIPSTART);
snprintf(buf, sizeof(buf), "\"%s\",%d", ip, port);
send_at_cmd (buf);
}
*/
// 打印输出全局缓冲区内容,即日志,通过USART1重定向了printf后显示到串口终端
void print_log_info (char *p_str)
{
printf ("\r\n%s:%s", p_str, atcmd_recv_buff.buff);
}
// 字符串清理
void sds_clean(sdstring *psds)
{
memset(psds->buff, 0, sizeof(psds->buff));
psds->pos=0;
}
// 字符串长度
int sds_length(sdstring *psds)
{
return psds->pos;
}
// 字符串追加
int sds_append_char(sdstring *psds, char ch)
{
if(psds->pos >= sizeof(psds->buff)-1)
{
return -1;
}
psds->buff[psds->pos]=ch;
psds->pos++;
return 0;
}
// at_cmd.h
#pragma once
#include
#include
#include "usart.h"
#include "setup.h"
/*--------------发送-----------------*/
// at命令头
#define AT_CMD_PREFIX "AT+"
#define CHAR_PLUS '+'
#define CHAR_CR '\r'
#define CHAR_POWER '^'
#define AT_CONFIRM "\r\n"
#define AT_FORMAT "ATE0Q0V1" // ATE1/0 回显/不回显字符; ATQ1/0 返回/不返回结果码; ATV1/0 返回/不返回结果码
// ATV1/0 决定了收到GPRS模块回复的数据是 <字符串> OK 或 <数字> 0
#define AT_AT "AT" // AT命令测试,返回OK
#define AT_ATI "ATI" // 查询固件版本信息
#define AT_CCID "AT+CCID" // 查询SIM ,CCID用于判断是否插卡
#define AT_CREG "AT+CREG?" // 查询网络注册情况
#define AT_CGATT "AT+CGATT=1" // 1.附着网络,返回OK
#define AT_CGATT_1 "AT+CGACT=1,1" // 2.激活PDP,返回OK,即可正常上网
#define AT_CIPSTART "AT+CIPSTART=\"TCP\"," // 连接服务端
#define AT_CON_TCP "AT+CIPSTART=\"TCP\",\"123.58.34.245\",80" // 连接服务端,IP和PORT目前为测试取值
#define AT_CON_IP "123.58.34.245"
#define AT_CON_PORT 80
#define AT_CIPSEND "AT+CIPSEND=20" // 返回>,就可以输入要发送的内容20表示有20个字节
#define AT_TMP_STRING "1234567890123456789" // 19个字符有效字符
#define AT_CIPCLOSE "AT+CIPCLOSE=1" // 关闭连接
#define AT_CIPSHUT "AT+CIPSHUT" // 关闭 GPRS/CSD PDP 场景
#define AT_CIPTMODE_START "AT+CIPTMODE=1" // 启动透传模式
#define AT_CIPTMODE_QUIT "AT+CIPTMODE=0" // 停止透传模式
#define PARSE_CMD_OK 0
#define PARSE_CMD_ERR -1
#define PARSE_CMD_NEEDMORE 1
typedef struct _sdstring {
int pos;
char buff[128];
} sdstring;
// 逐个发送AT命令集
void send_all_at_cmd (void);
// 发送单个AT命令,打印提示日志
void send_at_cmd (char * p_cmd);
// 接收发送命令后GPRS通过串口端自动回复的数据
char* receive_data (void);
// 往连接GPRS串口的USART2串口中按字节(8bit)逐个发送数据
void send_USART2 (char *pdata, int len);
// 打印输出全局缓冲区,即每次数据收发的日志信息
void print_log_info (char *p_str);
// void send_connect_cmd (char *ip,int port);
// 字符串处理
void sds_clean(sdstring *psds);
int sds_append_char(sdstring *psds, char ch);
int sds_length(sdstring *psds);
// 自定义的格式化输出
// void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
// setup.c
#include "Setup.h"
static __IO u32 TimingDelay;
/**
* @brief 启动系统滴答定时器 SysTick
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0 库版本
if (SysTick_Config(SystemCoreClock / 100000)) // ST3.5 库版本
{
/* Capture error */
while (1);
}
// 关闭滴答定时器
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief us延时程序,10us为一个单位
* @arg nTime Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
// 使能滴答定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
/**
* @brief 获取节拍程序
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
/*********************************************END OF FILE**********************/
// led.h
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
#define ON 0
#define OFF 1
/* 带参宏,可以像内联函数一样使用 */
#define LED1(a) if (a) \
GPIO_SetBits(GPIOB,GPIO_Pin_5); \
else \
GPIO_ResetBits(GPIOB,GPIO_Pin_5)
#define LED2(a) if (a) \
GPIO_SetBits(GPIOE,GPIO_Pin_5); \
else \
GPIO_ResetBits(GPIOE,GPIO_Pin_5)
void LED_Config(void);
#endif // __LED_H
// led.c
#include "led.h"
/*
* @ LED 初始化I/O控制
*/
void LED_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启GPIOB的外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*选择要控制的GPIOB引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
/*调用库函数,初始化GPIOB5*/
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*选择要控制的GPIOE引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
/*调用库函数,初始化GPIOE5*/
GPIO_Init(GPIOE, &GPIO_InitStructure);
/* 关闭led灯 */
GPIO_SetBits(GPIOB, GPIO_Pin_5);
GPIO_SetBits(GPIOE, GPIO_Pin_5);
}
/*********************************************END OF FILE**********************/