历史上的今天
返回首页

历史上的今天

今天是:2024年10月15日(星期二)

正在发生

2020年10月15日 | 给android设备增加串口功能

2020-10-15 来源:eefocus

环境:

主机:WIN7

开发环境:MDK4.23


功能:

打开Android手机或者平台的蓝牙,通过蓝牙连接蓝牙转串口板,通过蓝牙转串口板的串口与需要调试的串口设备相连


说明:

1.PCB为我同学hunter绘制,他同时是stm32的高手,感谢他提供的支持.

2.制作了一个蓝牙转串口的板子,Android设备连接上这个板子,就相当于增加了一个串口.

3.单片机选用的是STM32F101C8,蓝牙模块选用的是HC05.HC05本身就是一个蓝牙转串口模块,再增加一个单片机的作用是可以通过单片机来配置波特率等参数.

4.蓝牙转串口板可以用MINI USB来供电,或者用3.7V锂电池来供电,板子上带有充电管理芯片,由于没锂电池,充电这块还没有测试.

5.上位机程序(Android上的串口助手)暂时没有时间写,可以在安卓市场上搜索"蓝牙串口"下一个串口助手.

6.在上位机发送指定格式可以配置波特率,例:AT+BAUD9600END


实物图:


电路图:

第1部分:

图片较大,部分没有显示.可以在新窗口打开图片来看到全部内容

第2部分:


下位机程序:

public.h

#ifndef _PUBLIC_H_

#define _PUBLIC_H_

 

//公共头文件

#include "main.h"

#include "string.h"

#include "stdlib.h"

#include "stm32f10x_tim.h"

 

//宏定义

#define U8 unsigned char

#define U16 unsigned short

#define U32 unsigned long

 

//蓝牙转串口的缓存长度

#define LEN_BT_STACK 10

 

//蓝牙波特率设置命令

#define BT_BAUD_4800 "AT+UART=4800,0,0"

#define BT_BAUD_9600    "AT+UART=9600,0,0"

#define BT_BAUD_19200 "AT+UART=19200,0,0"

#define BT_BAUD_38400 "AT+UART=38400,0,0"

#define BT_BAUD_57600 "AT+UART=57600,0,0"

#define BT_BAUD_115200 "AT+UART=115200,0,0"

#define DEFAULT_BAUD 9600

 

//定义flash页大小

#if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || (STM32F10X_CL) || defined (STM32F10X_XL)

  #define FLASH_PAGE_SIZE    ((uint16_t)0x800)

  #define FLASH_PAGES_TO_BE_PROTECTED (FLASH_WRProt_Pages12to13 | FLASH_WRProt_Pages14to15)  

#else

  #define FLASH_PAGE_SIZE    ((uint16_t)0x400)

  //需要关闭写保护的页面

  #define FLASH_PAGES_TO_BE_PROTECTED (FLASH_WRProt_Pages60to63)  

#endif

 

//定义操作的flash的始末地址63K-64K

#define BANK1_WRITE_START_ADDR  ((uint32_t)0x0800FC00)

#define BANK1_WRITE_END_ADDR    ((uint32_t)0x08010000)

 

//数据结构

 

//通过蓝牙发过来的串口2的数据堆栈

//数据结构为循环队列,读写缓冲

#define LEN_BUF 512

struct _FIFO_Stack

{

unsigned char buf[LEN_BUF];

short ptr_r;

short ptr_w;

};

 

//数据流式符合字符串头检索

#define LEN_MATCH_STRING_HEADER 9

struct _match_string_header

{

char match[LEN_MATCH_STRING_HEADER];

int state;

};

 

//数据流式符合字符串尾检索,并提取数据结构

#define LEN_MATCH_STRING_TAIL 3

struct _match_string_tail

{

char match[LEN_MATCH_STRING_TAIL];

int state; //当前状态/下标

int value; //最后取得的值

int max_len; //数据最大长度

char capture_string[10];

int capture_index; //当前捕获数据下标

struct _match_string_header match_string_header; //用来比较尾是否正确

int flag; //捕获数据状态或是捕获字符尾状态

};

 

//修改flash

struct _edit_flash

{

unsigned short buf[512];

int flag; //判断flash是否被修改过

int baud; //需要写入/读出的波特率

};

 

//公共变量

//声明串口结构体

extern USART_InitTypeDef USART_InitStructure;

 

//声明FIFO堆栈给UART2使用

extern struct _FIFO_Stack fifo_uart2;

 

//声明FIFO堆栈给UART1使用

extern struct _FIFO_Stack fifo_uart1;

 

//声明修改flash结构体

extern struct _edit_flash edit_flash;

 

//公共函数

//按照蓝牙转串口的格式发送指令

void send_bt_cmd(char *str);

 

//循环缓冲方法

//初始化

void init_fifo_stack(struct _FIFO_Stack *stack);

//读取全部

//成功返回字节数,失败返回-1

short read_all_fifo_stack(struct _FIFO_Stack *stack,unsigned char *buf);

//写入1个字节

//失败返回-1,成功返回1

int write_byte_fifo_stack(struct _FIFO_Stack *stack,unsigned char byte);

 

//数据流式符合字符串头检索方法

//初始化

//成功返回1,失败返回0

int init_match_string_header(struct _match_string_header *m_str,char *buf);

//返回-1失败,返回0正在运行,返回1成功

int match_string_header_state(struct _match_string_header *m_str,char ch);

 

//数据流式符合字符串尾检索,并提取数据结构方法

//初始化

//成功返回1,失败返回0

int init_match_string_tail(struct _match_string_tail *m_str,char *buf,int max_len);

//返回-1失败,返回0正在运行,成功返回得到的数据

int match_string_tail_state(struct _match_string_tail *m_str,char ch);

 

//flash操作

//打开需要操作页面的写保护

void open_write_lock();

//向flash中写入数据,1024字节,512个半字

//成功返回写入的字节数,失败返回-1

int write_flash(unsigned short *buf);

//读取flash,读取1024字节,512半字

//成功返回读取的字节数,失败返回-1

int read_flash(unsigned short *buf);

 

//读取flash,获得flag和baud

//成功返回波特率,失败返回-1

int read_baud(struct _edit_flash *edit);

//写入波特率到flash

//成功返回1,失败返回0

int write_baud(struct _edit_flash *edit,int baud);

 

#endif

 


public.c:


#include "public.h"

 

//公共变量

//定义串口结构体

USART_InitTypeDef USART_InitStructure;

 

//声明FIFO堆栈给UART2使用

struct _FIFO_Stack fifo_uart2;

 

//声明FIFO堆栈给UART1使用

struct _FIFO_Stack fifo_uart1;

 

//声明修改flash结构体

struct _edit_flash edit_flash;

 

//按照蓝牙转串口的格式发送指令

void send_bt_cmd(char *str)

{

while(*str != '')

{

USART_SendData(USART2,*str++); //发送一位数据

while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕

}

 

USART_SendData(USART2,'r'); //发送一位数据

while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕

USART_SendData(USART2,'n'); //发送一位数据

while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕

}

 

//循环缓冲方法

//初始化

void init_fifo_stack(struct _FIFO_Stack *stack)

{

stack->ptr_r = 0;

stack->ptr_w = 0;

memset(stack->buf,0,LEN_BUF);

}

 

//读取全部

//成功返回字节数,失败返回0

short read_all_fifo_stack(struct _FIFO_Stack *stack,unsigned char *buf)

{

short i = 0;

short j = 0;

short len = 0;

short len2 = 0;

 

//如果已经读完,则不读

if (stack->ptr_r - stack->ptr_w == 0 ||

stack->ptr_r - stack->ptr_w == -1)

{

return -1;

}

 

//如果读指针小于写指针

if (stack->ptr_r < stack->ptr_w)

{

len =  stack->ptr_w - stack->ptr_r;

for (i = 0;i < len;i++)

{

   buf[i] = stack->buf[stack->ptr_r++];

}

return len;

}

else

{

//读指针大于写指针的情况

len = (LEN_BUF - 1) - stack->ptr_r + 1;

len2 = stack->ptr_w;

    for (i = 0;i < len;i++)

{

buf[j++] = stack->buf[stack->ptr_r++];

}

stack->ptr_r = 0;

for (i = 0;i < len2;i++)

{

buf[j++] = stack->buf[stack->ptr_r++];

}

return (len + len2);

}

}

 

//写入1个字节

//失败返回-1,成功返回1

int write_byte_fifo_stack(struct _FIFO_Stack *stack,unsigned char byte)

{

//如果已经写完,则不写

if (stack->ptr_w - stack->ptr_r == -1)

{

return -1;

}

 

stack->buf[stack->ptr_w++] = byte;

 

//判断是否已经写满

if (stack->ptr_w == LEN_BUF)

{

stack->ptr_w = 0;

}

}

 

//数据流式符合字符串头检索方法

//初始化

//成功返回1,失败返回0

int init_match_string_header(struct _match_string_header *m_str,char *buf)

{

int len = 0;

int i = 0;

len = strlen(buf);

if (len > LEN_MATCH_STRING_HEADER)

{

return 0;

}

m_str->state = 0;

for (i = 0;i < len;i++)

{

m_str->match[i] = buf[i];

}

m_str->match[i] = '';

return 1;

}

 

//返回-1失败,返回0正在运行,返回1成功

int match_string_header_state(struct _match_string_header *m_str,char ch)

{

if (ch == m_str->match[m_str->state])

{

m_str->state++;

if (m_str->match[m_str->state] == '')

{

m_str->state = 0;

return 1;

}

else

{

return 0;

}

}

else

{

m_str->state = 0;

return -1;

}

}

 

//数据流式符合字符串尾检索,并提取数据结构方法

//初始化

//成功返回1,失败返回0

int init_match_string_tail(struct _match_string_tail *m_str,char *buf,int max_len)

{

int len = 0;

int i = 0;

len = strlen(buf);

if (len > LEN_MATCH_STRING_TAIL)

{

return 0;

}

m_str->state = 0;

m_str->value = 0;

m_str->max_len = max_len;

m_str->capture_index = 0;

m_str->flag = 0;

for (i = 0;i < len;i++)

{

m_str->match[i] = buf[i];

}

m_str->match[i] = '';

init_match_string_header(&(m_str->match_string_header),m_str->match);

return 1;

}

 

//返回-1失败,返回0正在运行,成功返回得到的数据

int match_string_tail_state(struct _match_string_tail *m_str,char ch)

{

int flag = 0;

//判断是否捕获数据状态还是捕获字符尾状态

if (m_str->flag || ch == 'E')

{

//捕获字符尾状态

m_str->flag = 1;

flag = match_string_header_state(&(m_str->match_string_header),ch);

if (flag == -1)

{

//初始化数据

m_str->state = 0;

m_str->capture_index = 0;

m_str->flag = 0;

}

if (flag == 1)

{

m_str->capture_string[m_str->capture_index] = '';

m_str->value = atoi(m_str->capture_string);

//初始化数据

m_str->state = 0;

m_str->capture_index = 0;

m_str->flag = 0;

return m_str->value;

}

return flag;

}

else

{

//捕获数据状态

if (ch < '0' || ch > '9')

{

return -1;

}

//当已经达到最大数据长度且当前数据不是

//当不是数据字符返回错误

if (m_str->capture_index >= m_str->max_len)

{

m_str->state = 0;

m_str->capture_index = 0;

m_str->flag = 0;

return -1;

}

else

{

m_str->capture_string[m_str->capture_index++] = ch;

//如果达到最大长度,则置为捕获字符状态

if (m_str->capture_index >= m_str->max_len)

{

m_str->flag = 1;

}

return 0;

}

}

}

 

//打开需要操作页面的写保护

void open_write_lock()

{

uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0x0;

volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;

 

//解锁flash控制器

FLASH_Unlock();

 

//得到所有已经被写保护的页面号,如果被写保护则置0,没有则置1

WRPR_Value = FLASH_GetWriteProtectionOptionByte();

 

//需要写保护的页面置1,不需要的置0

ProtectedPages = ~(WRPR_Value | FLASH_PAGES_TO_BE_PROTECTED);

//检查需要的页是否被写保护

if((WRPR_Value | (~FLASH_PAGES_TO_BE_PROTECTED)) != 0xFFFFFFFF )

{

//擦除小信息模块,关闭写保护

FLASHStatus = FLASH_EraseOptionBytes();

//如果不是所有页面都需要打开写保护

if(ProtectedPages != 0x0)

{

  //将其他页面置位写保护

  FLASHStatus = FLASH_EnableWriteProtection(ProtectedPages);

}

//复位系统,重新载入小信息

NVIC_SystemReset();

}

}

 

//向flash中写入数据,1024字节,512个半字

//成功返回写入的字节数,失败返回-1

int write_flash(unsigned short *buf)

{

uint32_t EraseCounter = 0x0,Address = 0x0;

uint32_t WRPR_Value = 0xFFFFFFFF;

uint32_t NbrOfPage;

volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;

int i = 0;

 

//得到需要操作的页面数

NbrOfPage = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FLASH_PAGE_SIZE;

 

//得到所有已经被写保护的页面号,如果被写保护则置0,没有则置1

WRPR_Value = FLASH_GetWriteProtectionOptionByte();

//判断此页面是否被写保护,如果没有写保护则进行操作

if ( (WRPR_Value & FLASH_PAGES_TO_BE_PROTECTED) != 0x00)

{

//清除所有等待标志位

FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP|FLASH_FLAG_PGERR |FLASH_FLAG_WRPRTERR);

//擦数指定页面

for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)

{

FLASHStatus = FLASH_ErasePage(BANK1_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));

}

//得到操作flash的起始地址

Address = BANK1_WRITE_START_ADDR;

//写flash,每次写2个字节

while((Address < BANK1_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))

{

FLASHStatus = FLASH_ProgramHalfWord(Address, buf[i++]);

Address = Address + 2;

}

 

return i;

}

else

推荐阅读

史海拾趣

FRIWO公司的发展小趣事

作为全球化的技术型企业,FRIWO在全球范围内设立了研发、生产和营销部门,以满足不同市场的需求。FRIWO的电源解决方案业务部(FPS)专注于为客户量身订做电源解决方案,其客户群遍布医疗科技、IT通讯、家用电器、移动工具以及工业应用等多个领域。为了更好地服务本地客户,FRIWO在不同地区设立了分支机构,确保能够快速响应客户需求并提供专业的技术支持和服务。这种全球化布局与本地化服务的策略,使得FRIWO在激烈的市场竞争中保持了强劲的竞争力。

BOWEI公司的发展小趣事

FRIWO公司一直将创新视为企业发展的核心驱动力。公司不断投入研发资金,引进高端人才,致力于新技术、新产品的开发和应用。通过持续的技术创新,FRIWO在电源变换器、电源充电器、开关式电源供应器等领域取得了多项技术突破和专利成果。这些技术成果不仅提升了FRIWO产品的性能和品质,也为客户提供了更加高效、可靠的电源解决方案。

Amphenol Aerospace公司的发展小趣事

近年来,FRIWO与印度UNO MINDA集团建立了战略合作关系,共同开发印度电动汽车市场。UNO MINDA集团投资1500万欧元收购FRIWO AG的部分股权,这一交易标志着FRIWO在电动汽车领域的进一步拓展。双方合作将结合FRIWO在电源和充电技术方面的优势与UNO MINDA在印度市场的深厚基础,为印度市场提供完整的电驱动系统解决方案。这一合作不仅增强了FRIWO在全球市场的影响力,也为印度电动汽车市场的发展注入了新的活力。

Eclipse Magnetics公司的发展小趣事

为了更好地服务中国市场和亚太地区的客户,FRIWO在中国深圳设立了生产基地——飞煌德商科技(深圳)有限公司。该生产基地负责开发、生产、加工电源变换器、电源充电器等产品,并承担自产产品及同类商品的批发、佣金代理、进出口及相关配套业务。飞煌德商科技(深圳)有限公司的成立和发展,不仅增强了FRIWO在中国市场的竞争力,也为公司的全球化战略提供了有力支持。通过不断优化生产流程、提升产品质量和服务水平,飞煌德商科技(深圳)有限公司逐渐成为了FRIWO在全球供应链中的重要一环。

Custom Components Inc公司的发展小趣事

在CCI的发展历程中,人才培养和团队建设始终是公司发展的重要保障。公司注重员工的个人成长和职业发展,为员工提供多样化的培训和发展机会。

同时,CCI还建立了完善的激励机制和福利制度,激发员工的工作热情和创造力。通过加强团队合作和文化建设等方式,公司营造了一个积极向上、充满活力的工作氛围。这种良好的团队氛围不仅提高了员工的工作效率和满意度,也为公司的持续发展提供了有力的人才保障。

睿赫(crechip)公司的发展小趣事

在公司的快速发展过程中,睿赫公司高度重视团队建设和人才培养。公司建立了一套完善的人才选拔和培养机制,吸引了一批优秀的电子工程师和技术人才加入。同时,公司还注重员工的职业发展和福利待遇,为员工提供了广阔的发展空间和良好的工作环境。

通过团队建设和人才培养,睿赫公司的研发团队逐渐壮大,创新能力也得到了极大的提升。这使得公司能够在激烈的市场竞争中保持领先地位,不断推出具有竞争力的新产品。

问答坊 | AI 解惑

Protel中如何設置手動布線的線寬同過孔大小?

PlacementTools工具栏在Protel  PCB编辑环境下,鼠标点中PlacementTools工具栏的划线工具,然后鼠标点在划线起点上,敲击键盘Tab键,弹出对话框,在Traca Width框中敲进需要的线宽值,同时在Via Diameter 栏和Via Hole Size栏可以修改穿导孔的 ...…

查看全部问答>

浅谈OFDM原理及其应用

摘 要:本文从OFDM系统模型入手,先介绍OFDM的基本原理,再介绍OFDM在数字音频广播(DAB)和数字电视广播(DVB)中的应用,最后介绍OFDM在通信领域(无线ATM网络演示设备!无线局域网!非对称数字用户线和多输入多输出多媒体技术)中的应用\"…

查看全部问答>

PIC系列单片机数据存储器的特点和功能(上)

PIC系列单片机品种虽多,但各产品内部硬件资源的数据存储器设置仍是很有规律的。笔者以PIC16C71A和PIC16C63/65/65A两个品种为实例,查看它们片内数据存储器的结构,找出它们的特点并说明某些寄存器的主要功能,以供用户快速编程。表1和表2分别是PIC ...…

查看全部问答>

atmega8自制摄像头

使用atmega8自制摄像头 详细资料见附件…

查看全部问答>

为什么MC52i经常读不到短信?

使用mc52i,每隔半小时通过向服务器传送一个UDP数据包,同时服务器也向mc52i发送短信,但是使用AT+CMGR指令,经常读取不到短信。 有没有做过类似工作的朋友帮帮忙,已经调试了几天了,问题依然存在…

查看全部问答>

做过GRPS数据传输的请进!!!!!!!

第一次做GPRS数据传输,用的是华为的GTM900B。希望各位能给个AT指令建立连接,传输数据的例子。 邮箱:amarantine33520@163.com 不胜感激!!!!!!!…

查看全部问答>

刚毕业的大学生去东软总部(沈阳)做嵌入式开发适合吗?

刚毕业的大学生去东软总部(沈阳)做嵌入式开发适合吗?请回答我!!!…

查看全部问答>

问下各位大哥大姐,platform builder 中的仿真器是否可以用模拟器来完成仿真?

问下各位大哥大姐,platform builder 中的仿真器是否可以用模拟器来完成仿真? 拜托了…

查看全部问答>

LM3S 12864驱动问题

void S12864_SysCtl_Init(void) {         SysCtlPeripheralEnable(S12864_PERIPH);         GPIODirModeSet(S12864_PORT,S12864_SCLK_PIN|S12864_CS_PIN|S12864_SID_PIN,GPIO_DIR_MODE_OUT);   ...…

查看全部问答>

只有一个定时器的430,能否输出PWM的同时还能定时中断干其他活?

只有一个定时器的430,能否输出PWM的同时还能定时中断干其他活? 比如系统输出30K的PWM波形,同时还能有0.5秒的定时中断去执行其它任务。 大大能否贴个简单的代码指导一下啊?…

查看全部问答>