驱动本身很简单,只是将模块的三个CDC串口注册成了普通的字符串驱动,因此可以直接使用AT指令进行通信,速度自然是会比普通串口快的,至于快多少不知道,没去测,稳定性感觉应该反而是不如232的,至少我是这么感觉的,毕竟是因为代码协议复杂化了,所以稳定性反而会造成下降。
usbhost.rar 这个文件解压到components\drivers\usb\usbhost替换源文件。
inclue_drivers.rar 这个文件解压到components\drivers\include\drivers替换源文件。
这里需要注意下,由于CDC走AT指令是有接收任意字节数返回概念的,而这点在官方驱动里是没有的,因此为了解决这个问题,官方驱动里面我增加了一个专门用于接收任意字节数的函数,用于适应CDC的这种特性,不然功能没法玩。具体的因为个人代码比较烂,不多说了。
这里给出下简单的应用代码。
while (1) {
if (rt_device_find("CDC00") != RT_NULL) {
rt_thread_delay(2000);
if (rt_device_find("CDC00") != RT_NULL) {
{
rt_thread_startup(rt_thread_create("state", led_run_entry, RT_NULL, 1024, 21, 10));
}
rt_hw_modem_init("CDC00", "3GNET", "", "");
{
extern void iot_app_init(void);
iot_app_init();
}
{
extern void master_start(void);
master_start();
}
return 0;
}
}
rt_thread_delay(1000);
}
由于USB驱动初始化到挂载成功是有过程的,所以需要判断是否存在才能进行操作,具体使用也简单。这里给出AT使用函数实体。
static int at_command(rt_device_t handle, char * buffer, const char *at, const char *ack, int timeout)
{
int len;
uint32_t totlen;
uint32_t u32Len;
uint32_t u32RecvLen;
uint8_t *u8Buffer = (uint8_t *)buffer;
// 如果设备不存在,被注销了
if(rt_object_get_type(&handle->parent) != RT_Object_Class_Device)
{
return -3;
}
u32Len = timeout;
rt_device_control(handle, RT_DEVICE_CTRL_TIMEOUT, &u32Len);
sprintf(buffer, "%s", at);
AT_CMD_TRACE(buffer);
rt_device_write(handle, 0, buffer, strlen(buffer));
// 如果设备不存在,被注销了
if(rt_object_get_type(&handle->parent) != RT_Object_Class_Device)
{
return -3;
}
totlen = 512;
len = rt_device_read(handle, 0, u8Buffer, totlen);
if(len <= 0) {
return -1;
}
totlen -= len;
u8Buffer += len;
u32RecvLen = len;
// 如果设备不存在,被注销了
if(rt_object_get_type(&handle->parent) != RT_Object_Class_Device)
{
return -3;
}
u32Len = 10;
rt_device_control(handle, RT_DEVICE_CTRL_TIMEOUT, &u32Len);
do {
// 如果设备不存在,被注销了
if(rt_object_get_type(&handle->parent) != RT_Object_Class_Device)
{
return -3;
}
len = rt_device_read(handle, 0, u8Buffer, totlen);
if(len <= 0) {
break;
}
totlen -= len;
u8Buffer += len;
u32RecvLen += len;
} while(totlen > 0);
buffer[u32RecvLen] = 0;
if(u32RecvLen < 2) {
return -2;
}
AT_ACK_TRACE(buffer);
if(strstr(buffer, ack) == RT_NULL) {
return -1;
}
return 0;
}
调用方式
int air724_at_dial(rt_device_t handle, uint8_t *buffer, const char apn)
{
uint32_t u32Len;
/
** Step 1, 一般命令,设置应答超时为5秒,接收时间间隔为1秒
/
// u32Len = 5000;
// rt_device_control(handle, RT_DEVICE_CRTL_TIMEOUT, &u32Len);
// u32Len = 1000;
// rt_device_control(handle, RT_DEVICE_CTRL_INTERVAL, &u32Len);
/
** Step 2, AT指令测试
*/
if(at_command(handle,(char )buffer, "AT\r\n", "OK", 1000) < 0) {
return -1;
}
/
** Step 3, 关闭回显
*/
if(at_command(handle,(char *)buffer, "ATE0\r\n", "OK", 1000) < 0) {
return -1;
}
// 确认模块能联网
if(at_command(handle, (char *)buffer, "AT+CGATT?\r\n", "OK", 5000) < 0) {
return 0;
} else {
char *start;
start = strstr((char )buffer,"+CGATT: ");
if(start == RT_NULL) {
return 0;
}
start += 8;
if(strncmp(start, "1", 1) != 0) {
rt_kprintf("modem can't connect to internect\r\n");
return 0 ;
}
}
/
** Step 8, 检测模块是否注册上网
*/
if(at_command(handle,(char )buffer, "AT+CREG?\r\n", "OK",5000) < 0) {
return 0;
}
/
** Step 9, 查询基站信息
*/
if(at_command(handle,(char *)buffer, "AT+CGREG?\r\n", "OK",5000) < 0) {
return 0;
}
// if(at_command(handle,(char )buffer, "AT+CGREG=?\r\n", "OK", 5000) < 0) {
// return 0;
// }
/
** Step 10, 查看GPRS网络帮助信息
*/
if(at_command(handle,(char )buffer, "AT+CGDCONT=?\r\n", "OK", 5000) < 0) {
return 0;
}
/
** Step 11, Before active, use this command to set PDP context.此后的命令可能等待较长
*/
sprintf((char *)&buffer[512], "AT+CGDCONT=1, "IP", "%s"\r\n", apn);
if(at_command(handle,(char *)buffer, (char )&buffer[512], "OK", 100000) < 0) {
return 0;
}
/
** Step 12, This command is to start PPP translation.
*/
if(at_command(handle,(char )buffer, "ATD99#\r\n", "CONNECT", 100000) < 0) {
at_command(handle,(char *)buffer, "+++", "OK", 100000);
rt_kprintf("enter ppp success!\r\n");
return 0;
}
if(strstr((char *)buffer, "DISCONNECT") != RT_NULL) {
at_command(handle,(char *)buffer, "+++", "OK", 100000);
return 0;
}
return 1;
}
至于驱动打开什么的那就不发了,怕侮辱你们智商。
原作者:xiao苦