ATK-M750C 4G模块移植到STM32F103、F407

本文讲解是以F4为例,F1接线和F4一模一样,代码部分串口配置有一点区别,具体自己看代码,文末都有给出

先准备一个ATK-M750C 4G模块,然后下载正点原子官方资料4G Cat1 DTU通信模块ATK-IDM751C.IDM750C — 正点原子资料下载中心 1.0.0 文档 (openedv.com)

下载完成后打开5,实例源码(基于STM32)文件夹,里面有一个压缩包,选择库函数版本,适合探索者F407开发板,再选择(库函数版本,适合探索者F407开发板)  ATK-M750 TTL通讯(链接见文末)【1】

解压出来后打开USER双击ATK-M750.uvprojx打开工程,直接编译会报错,如图所示

573a6c33fbb06bcba042b3fe04c50187.png

 是因为没有勾选C99 Mode,打开魔术棒勾选此处即可

918bd4226ab901c1556b8193266b9b9d.png

7329bf05105c8b85f49c75fb951c334b.png

 重新编译,没有报错

此时自己再解压一个官方的串口demo例程【2】,或者使用我整理的(链接在文末,所有提到的文件均放在一起并与文中红色序号对应)

其中usart.c除了初始化串口1,还要初始化串口2,代码如下(注:基于正点原子demo修改)

#include "sys.h"
#include "usart.h"
#include "ring_buffer.h"
#include "string.h"

//重定义fputc函数 
int fputc(int ch, FILE *f)
{
    while ((USART1->SR & 0X40) == 0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;
    return ch;
}

//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA = 0;       //接收状态标记	

//初始化IO 串口1 
//bound:波特率
void uart_init(u32 bound)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//使能USART1时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟

    //串口1对应引脚复用映射
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //GPIOA9复用为USART1
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //GPIOA10复用为USART1
    //串口2引脚复用映射
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); //GPIOA2复用为USART2
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); //GPIOA3复用为USART2


    //USART1端口配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9,PA10
    
    //USART2    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; //GPIOA2与GPIOA3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
    GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA2,PA3

    //USART1 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    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); //初始化串口1
    
    //USART2 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    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_Cmd(USART1, ENABLE);  //使能串口1 
    USART_Cmd(USART2, ENABLE);  //使能串口 2

    USART_ClearFlag(USART1, USART_FLAG_TC);
    USART_ClearFlag(USART2, USART_FLAG_TC);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启接受中断

    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器、
    
    //Usart2 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、
}

extern ring_buffer rb;

void USART1_IRQHandler(void)                    //串口1中断服务程序
{
    u8 Res;

    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
        Res = USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
    }
} 

void usart1_send_data(u8 *data, u32 size)
{
    for(u32 i = 0; i < size; i++)
    {
        while((USART1->SR & 0X40) == 0);

        USART1->DR = data[i];
    }
}
extern ring_buffer p_uart2_rxbuf;
void USART2_IRQHandler(void)                        //串口2中断服务程序
{
    u8 Res;

    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) 
    {
        Res = USART_ReceiveData(USART2);            //读取接收到的数据

        RB_Write_Byte(&p_uart2_rxbuf, Res);            //放入缓存
    }
}

void usart2_send_data(u8 *data, u32 size)
{
    for(u32 i = 0; i < size; i++)
    {
        while((USART2->SR & 0X40) == 0);

        USART2->DR = data[i];
    }
}

usart.h代码如下(注:基于正点原子demo修改)

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "stm32f4xx_conf.h"
#include "sys.h" 

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
void usart1_send_data(u8 *data, u32 size);
void usart2_send_data(u8 *data, u32 size);
#endif

参考官方自带的ATK-M750C的demo,可以看到使用了ringbuffer缓冲区,我们这里使用一个轻量级环形缓冲区即可,不需要外部SRAM,参考链接如下[开源]轻量级环形缓冲区Ring Buffer,非常适合用于MCU嵌入式平台的串口收发 - STM32/8 (51hei.com)

开源ringbuffer从GitHub下载后打开RingBuffer-main.zip(链接见文末)【3】

将其中的ring_buffer.c、ring_buffer.h添加到串口demo工程中,并在ring_buffer.h中添加头文件stm32f4xx.h

3b0cb6a33a4d7d68fcd0adff6e3d6f1c.png

 然后再ring_buffer.c中添加Reset功能,在ring_buffer.h中添加声明

uint8_t RB_Reset(ring_buffer *rb_handle)
{
    return rb_handle->head = rb_handle->tail = rb_handle->Length = 0 ;
}
uint8_t RB_Reset(ring_buffer *rb_handle);

然后把官方例程中的atk_m750.c和atk_m750.h放入到串口demo中,修改相关的头文件和ringbuffer函数,部分修改如下 

342472a373449044e3b6ed54e245ff3f.png

2130e498592906afc1e222dd2effe55b.png

 e8eb8a078c9e8dfcd173e728742aa3c2.png

 注意函数中的取地址符&

主函数main.c如下

#include "stm32f4xx.h"                  // Device header
#include "delay.h"
#include "led.h"
#include "OLED.h"
#include "sys.h"
#include "usart.h"

#include "ring_buffer.h"
#include "string.h"
#include "atk_m750.h"

#define DTU_TEST_DATA "ALIENTEK ATK-IDM750C TEST"

#define DTU_NETDATA_RX_BUF (1024)

static uint32_t dtu_rxlen = 0;
static uint8_t dtu_rxbuf[DTU_NETDATA_RX_BUF];

ring_buffer p_uart2_rxbuf;

int main(void) {
    int ret;
    uint32_t timeout = 0;
    uint8_t buf;
    uint8_t key;
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    uart_init(115200);    //串口初始化波特率为115200
    LED_Init();                //初始化与LED连接的硬件接口  
    
    RB_Init(&p_uart2_rxbuf, dtu_rxbuf, DTU_NETDATA_RX_BUF);
    
    printf("Wait for Cat1 DTU to start, wait 10s.... \r\n");
    {
        while( timeout <= 10 )   /* 等待Cat1 DTU启动,需要等待5-6s才能启动 */
        {   
            ret = dtu_config_init(DTU_WORKMODE_NET);    /*初始化DTU工作参数*/
            if( ret == 0 )
                break;
            timeout++;
            delay_ms(1000);
        }

        while( timeout > 10 )   /* 超时 */
        {
            printf("**************************************************************************\r\n");
            printf("ATK-DTU Init Fail ...\r\n");
            printf("请按照以下步骤进行检查:\r\n");
            printf("1.使用电脑上位机配置软件检查DTU能否单独正常工作\r\n");
            printf("2.检查DTU串口参数与STM32通讯的串口参数是否一致\r\n");
            printf("3.检查DTU与STM32串口的接线是否正确\r\n");
            printf("4.检查DTU供电是否正常,DTU推荐使用12V/1A电源供电,不要使用USB的5V给模块供电!!\r\n");
            printf("**************************************************************************\r\n\r\n");
            delay_ms(3000);
        }
    }
    printf("Cat1 DTU Init Success \r\n");

    dtu_rxlen = 0;
    RB_Reset(&p_uart2_rxbuf);

    /*  
        DTU进入透传状态后,就可以把它当成普通串口使用,必须确保:1.硬件连接完好 2.串口参数与DTU的保持一致
        注意:DTU每次上电需要一定的时间,在等待连接过程中,MCU可以向DTU发送数据并缓存在DTU中,等到与服务器连接上,DTU会自动将数据缓存数据全部转发到服务器上。
    */
    while (1)
    {
        if (RB_Get_Length(&p_uart2_rxbuf) > 0)          /*接收到DTU传送过来的服务器数据*/
        {
            RB_Read_Byte(&p_uart2_rxbuf, &buf);

            dtu_rxbuf[dtu_rxlen++] = buf;
            dtu_get_urc_info(buf);                      /*解析DTU上报的URC信息*/

            if (dtu_rxlen >= DTU_NETDATA_RX_BUF)        /*接收缓存溢出*/
            {
                usart1_send_data(dtu_rxbuf, dtu_rxlen); /*接收到从DTU传过来的网络数据,转发到调试串口1输出*/
                dtu_rxlen = 0;
            }
        }
        else
        {
            if (dtu_rxlen > 0)
            {
                usart1_send_data(dtu_rxbuf, dtu_rxlen); /*接收到从DTU传过来的网络数据,转发到调试串口1输出*/
                dtu_rxlen = 0;
            }

            LED0 = !LED0;
            delay_ms(100);
        }

//        key = KEY_Scan(0);
//        if(key == KEY0_PRES)
//        {
//            /*如果服务器格式对数据有要求,请修改对应的数据格式,这里只限于例程测试使用*/
//            send_data_to_dtu((uint8_t *)DTU_TEST_DATA, strlen(DTU_TEST_DATA));
//        }
    }
}


至此,已全部移植修改完毕,完整工程见文末链接中的【4】

注意,最重要的是接线,官方推荐供电为12V/1A,可以找一个常用的电源适配器(注意看输出电压电流是否符合)对其供电,VI接正极,G接负极

然后模块的TX接PA3、RX接PA2

PA9、PA10接USB TO TTL来打印串口信息

最后,如果你使用的是开发板,则模块的另一个G要接到开发板的GND实现共地,否则模块无法正常工作。

最后看一下现象(无SIM卡),先打开串口助手,打卡串口,选择波特率为115200,然后下载程序,复位,可以看到打印的信息。

5b92de310dbe6bde794f4ad4a9acf3d9.png

F1的代码见链接中的【5】

链接:https://pan.baidu.com/s/1Eh1913twcj9vrrCD3whZSA 
提取码:0htg

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值