技术标签: 单片机
单片机的世界从点灯开始。
RTL8762是BLE蓝牙芯片,SOC,是性能比51单片机高出很多的存在,甚至不弱于一些ARM32位单片机,不用来点灯真是太可惜。
关于蓝牙开始很多人都有误解,认为蓝牙就是可以连接电脑,播放歌曲。那是传统蓝牙给人们的印象太深刻了。蓝牙3.0以下版本都是传统蓝牙,追求的是HIFI,可以连续播放歌曲,而不用考虑功率。
蓝牙4.0版本(BLE蓝牙低功耗)以上是用来传少量的数据控制指令,而不是传歌曲这种流量大户,4.0、5.0不是3.0传统蓝牙的替代,是共存的。并且4.0、5.0在低功耗领域为蓝牙技术开辟了新的战场,以适应物联网时代的到来。物联网时代要时时在线,低功耗是必须的选择。
BLE可以干什么?
点灯---蓝牙点灯,或者叫无线点灯
RTL8762的世界也是从点灯开始。
本文所用源码基于BEE2-SDK-v1.2.0修改而来,BEE2-SDK-v1.2.0是RTL8762的SDK,官方管RTL8762系列叫小蜜蜂(BEE),非常巧合Zigbee也带一个BEE,看来物联网应该是蜜蜂建立的。BEE2-SDK-v1.2.0可从www.realmcu.com获得
原始工程路径:BEE2-SDK-v1.2.0\board\evb\ble_peripheral\peripheral.uvprojx
官方SDK有很多工程例子,本文用的是ble_peripheral
peripheral是外设意思,ble+peripheral
1、工程中的文件夹:
1、include(一些头文件,不需要修改)
2、lib(静态库,不需要修改)
3、cmsis(ARM的比较基础的东西,不需要修改)
4、peripheral(RTL8762的外设,sdk里有各种外设驱动源码,按需添加)
5、profile(一般不用修改,GATT的配置文件,可以建立自己的profile)
6、app(主要的应用实现,重点修改文件都在这里)
2、 peripheral下的文件
我加的这几个文件,源文件都在BEE2-SDK-v1.2.0\src\mcu\peripheral下,用什么加什么
rtl876x_io_dlps.c
rtl876x_uart.c
rtl876x_rcc.c
rtl876x_gpio.c
uart用来串口通讯,gipo用来点灯
3、app下的文件
ancs.c(原工程自带)
app_task.c(原工程自带,rtos任务创建)
main.c(原工程自带,主文件,初始化调度)
peripheral_app.c(原工程自带,消息处理)
overlay_mgr.c(原工程自带)
uart.c
只有UART.C是后来添加的,实现了UART基本封装,其他都是原有工程自带
BLE编程主要是处理各类消息,由peripheral_app.c负责。
main.c是应用入口,实现了main函数如下:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
board_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
这里的main函数完全不用修改,所有的RTL8762的程序都是这么写的。
board_init()是硬件初始化
*gap*是GAP初始化,GAP是BLE的重要概念
app_le_profile_init()是GATT初始化,GATT是BLE另一个重要概念
task_init()是OS_IF(freertos)的任务初始化,实时操作系统的任务创建
常用的应该就是这么几个
打个比方如果把蓝牙设备比作商店,那么GAP就是商店的基本信息,比如商店名,地理位置等。而GATT就是商店提供的服务,比如某一类商品,商品的价格,款式,尺寸。根据需要还可以上架新的GATT服务。
如果用BLE手机调试工具来看如下图所示:
其中,Generic Access就是GAP,Unknown Service 和Battery Service 是GATT
为什么BLE手机调试工具可以识别Battery Service,而不能识别Unknown Service。那是因为蓝牙标准组织给GATT服务提供了统一的编号,Battery Service有统一的编号,所以被识别出来,而Unknown Service本来就是自定义的服务,程序提供的编号不在统一编码内,BLE手机调试工具也就无法识别。
main.c 文件include了board.h文件 ,board.h文件是开发板定义文件。
其中以下定义根据需要开启,本文用到了UART和GPIO,所以USE_UART_DLPS和USE_GPIO_DLPS赋值为1,此处很关键,否则程序无法正常运行:
/* if use any peripherals below, #define it 1 */
#define USE_I2C0_DLPS 0
#define USE_I2C1_DLPS 0
#define USE_TIM_DLPS 0
#define USE_QDECODER_DLPS 0
#define USE_IR_DLPS 0
#define USE_RTC_DLPS 0
#define USE_UART_DLPS 1
#define USE_ADC_DLPS 0
#define USE_SPI0_DLPS 0
#define USE_SPI1_DLPS 0
#define USE_SPI2W_DLPS 0
#define USE_KEYSCAN_DLPS 0
#define USE_DMIC_DLPS 0
#define USE_GPIO_DLPS 1
#define USE_PWM0_DLPS 0
#define USE_PWM1_DLPS 0
#define USE_PWM2_DLPS 0
#define USE_PWM3_DLPS 0
点灯用P4_0和P4_1
#define GPIO_OUTPUT_PIN_0 P4_0
#define GPIO_OUTPUT_PIN_1 P4_1
#define GPIO_PIN_OUTPUT GPIO_GetPin(GPIO_OUTPUT_PIN_0)
#define GPIO_PIN_OUTPUT1 GPIO_GetPin(GPIO_OUTPUT_PIN_1)
UART用P3_0和P3_1
#define UART_TX_PIN P3_0
#define UART_RX_PIN P3_1
board初始化: PAD(管脚)、UART
void board_init(void)
{
/**
* @ led gpio init
*/
Pad_Config(GPIO_OUTPUT_PIN_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,
PAD_OUT_HIGH);
Pinmux_Config(GPIO_OUTPUT_PIN_0, DWGPIO);
Pad_Config(GPIO_OUTPUT_PIN_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,
PAD_OUT_HIGH);
Pinmux_Config(GPIO_OUTPUT_PIN_1, DWGPIO);
/**
* @ uart
*/
board_uart_init();
}
void board_uart_init(void)
void board_uart_init(void)
{
Pad_Config(UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pinmux_Config(UART_TX_PIN, UART0_TX);
Pinmux_Config(UART_RX_PIN, UART0_RX);
}
设备初始化:GPIO、UART
void driver_init(void)
{
/* Initialize GPIO */
RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_OUTPUT|GPIO_PIN_OUTPUT1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_ITCmd = DISABLE;
GPIO_Init(&GPIO_InitStruct);
//GPIO_InitStruct.GPIO_Pin = GPIO_PIN_OUTPUT1;
//GPIO_Init(&GPIO_InitStruct);
//lightUpLed();
/* uart init*/
driver_uart_init();
}
void driver_uart_init(void)
void driver_uart_init(void)
{
UART_DeInit(UART);
RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);
/* uart init */
UART_InitTypeDef UART_InitStruct;
UART_StructInit(&UART_InitStruct);
/* Config uart baudrate */
UART_InitStruct.div = BaudRate_Table[BAUD_RATE_115200].div;
UART_InitStruct.ovsr = BaudRate_Table[BAUD_RATE_115200].ovsr;
UART_InitStruct.ovsr_adj = BaudRate_Table[BAUD_RATE_115200].ovsr_adj;
UART_InitStruct.parity = UART_PARITY_NO_PARTY;
UART_InitStruct.stopBits = UART_STOP_BITS_1;
UART_InitStruct.wordLen = UART_WROD_LENGTH_8BIT;
UART_InitStruct.rxTriggerLevel = 16; //1~29
UART_InitStruct.idle_time = UART_RX_IDLE_2BYTE; //idle interrupt wait time
UART_Init(UART, &UART_InitStruct);
uart_sendString1("#### # ##### # # # #### ##### # ##### #### \r\n");
uart_sendString1(" # # # # # # # # # # # # # # # \r\n");
uart_sendString1(" # # # # # # # # # # # # # # # \r\n");
uart_sendString1(" ### # #### # # # # #### # # #### # # \r\n");
uart_sendString1(" # # # # # # ##### # # # # # # # \r\n");
uart_sendString1(" # # # # # # # # # # # # # # # \r\n");
uart_sendString1("#### ##### ##### ### # # # # # ##### ##### #### \r\n");
uart_sendString1(" ##### ##### \r\n");
uart_sendString1("Sarting......");
}
/*低电平点灯*/
void lightUpLed(void)
{
/* Light up LED0 */
GPIO_WriteBit(GPIO_PIN_OUTPUT, (BitAction)(0));
GPIO_WriteBit(GPIO_PIN_OUTPUT1,(BitAction)(0));
}
/*高电平灭灯*/
void lightDownLed(void)
{
/* Light down LED0 */
GPIO_WriteBit(GPIO_PIN_OUTPUT, (BitAction)(1));
GPIO_WriteBit(GPIO_PIN_OUTPUT1,(BitAction)(1));
}
/*闪灯*/
void flashLed(void)
{
for(uint32_t j=0;j<5;j++)
{
lightUpLed();
for (uint32_t i = 0; i < 100000; i++);
lightDownLed();
}
}
其中uart_senddata_continuous是官方DEMO里的函数
void uart_sendString1(char* str)
{
uint16_t demo_str_len = 0;
demo_str_len = strlen(str);
memcpy(String_Buf1, str, demo_str_len);
/* Send demo tips */
uart_senddata_continuous(UART, String_Buf1, demo_str_len);
}
在peripheral_app.c中,查找“BAS_READ_BATTERY_LEVEL”做如下修改
改成静态变量:static uint8_t battery_level = 90;
添加:battery_level++;
添加用于点灯:lightUpLed();
添加用于UART输出信息:uart_sendString1("Get BATTERY LEVEL\r\n");
case SERVICE_CALLBACK_TYPE_READ_CHAR_VALUE:
{
if (p_bas_cb_data->msg_data.read_value_index == BAS_READ_BATTERY_LEVEL)
{
static uint8_t battery_level = 90;
APP_PRINT_INFO1("BAS_READ_BATTERY_LEVEL: battery_level %d", battery_level);
uart_sendString1("Get BATTERY LEVEL\r\n");
bas_set_parameter(BAS_PARAM_BATTERY_LEVEL, 1, &battery_level);
battery_level++;
//trun_led(0);
lightUpLed();
}
}
app_task.c中增加timer的任务,回调函数是timer_callback;
另外用task方式建了一个uart任务,实验task方式处理UART。
void app_task_init()
{
// void *p_handle=NULL;
os_task_create(&app_task_handle, "app", app_main_task, 0, APP_TASK_STACK_SIZE,
APP_TASK_PRIORITY);
//timer task
if(os_timer_create(&p_handle,"timer",0,1000,true,timer_callback )== true)
{
os_timer_start(&p_handle);
}
else
{
//Timer failed to creat.
}
//uart task
os_task_create(&uart_task_handle, "uart", uart_task, 0, APP_TASK_STACK_SIZE,
APP_TASK_PRIORITY);
}
timer的任务的处理函数,回调函数负责闪烁LED(用了PAD方式,不是GPIO),timer_stop负责停止定时,闪烁停止;timer_restart负责重新定时,继续闪烁。
oid timer_callback(void *p_handle)
{
static uint8_t count =0;
if(count == 0)
{
Pad_Config(P4_0,PAD_SW_MODE,PAD_IS_PWRON,PAD_PULL_NONE,PAD_OUT_ENABLE,PAD_OUT_LOW);
count = 1;
}
else{
Pad_Config(P4_0,PAD_SW_MODE,PAD_IS_PWRON,PAD_PULL_NONE,PAD_OUT_ENABLE,PAD_OUT_HIGH);
count = 0;
}
}
void timer_stop(void){
os_timer_stop(&p_handle);
Pad_Config(P4_0,PAD_SW_MODE,PAD_IS_PWRON,PAD_PULL_NONE,PAD_OUT_ENABLE,PAD_OUT_HIGH);
}
void timer_restart(void){
os_timer_restart(&p_handle,100);
}
在peripheral_app.c中,查找“GAP_CONN_STATE_DISCONNECTED”,增加timer_restart(),实现在蓝牙断开后,LED继续闪烁。在“GAP_CONN_STATE_CONNECTED”后面增加timer_stop();,实现蓝牙连接后,LED停止闪烁。
case GAP_CONN_STATE_DISCONNECTED:
{
if ((disc_cause != (HCI_ERR | HCI_ERR_REMOTE_USER_TERMINATE))
&& (disc_cause != (HCI_ERR | HCI_ERR_LOCAL_HOST_TERMINATE)))
{
APP_PRINT_ERROR1("app_handle_conn_state_evt: connection lost cause 0x%x", disc_cause);
}
le_adv_start();
timer_restart();
}
break;
case GAP_CONN_STATE_CONNECTED:
{
uint16_t conn_interval;
uint16_t conn_latency;
uint16_t conn_supervision_timeout;
uint8_t remote_bd[6];
T_GAP_REMOTE_ADDR_TYPE remote_bd_type;
le_get_conn_param(GAP_PARAM_CONN_INTERVAL, &conn_interval, conn_id);
le_get_conn_param(GAP_PARAM_CONN_LATENCY, &conn_latency, conn_id);
le_get_conn_param(GAP_PARAM_CONN_TIMEOUT, &conn_supervision_timeout, conn_id);
le_get_conn_addr(conn_id, remote_bd, &remote_bd_type);
APP_PRINT_INFO5("GAP_CONN_STATE_CONNECTED:remote_bd %s, remote_addr_type %d, conn_interval 0x%x, conn_latency 0x%x, conn_supervision_timeout 0x%x",
TRACE_BDADDR(remote_bd), remote_bd_type,
conn_interval, conn_latency, conn_supervision_timeout);
timer_stop();
}
1、源码这里下载https://download.csdn.net/download/weixin_44067125/87995309
2、主要实现以下功能:
BATTERY LEVEL 读取电量自增1、点亮LED
自定义characteristic 发送HEX数据:0A点亮led,发送14熄灭led,发送其他LED闪烁
蓝牙未连接时,LED闪烁,连接时LED熄灭
3、BLE基本概念需要了解
4、RTOS实时操作系统要了解一些,至少知道创建task
5、KEIL编译,MPTOOL烧写
6、手机上的BLE调试工具需要安一个,我用的是沁恒家的
7、板子:RTL8762C 开发板 - 嘉立创EDA开源硬件平台
RTL8762的手册和SDK前前后后看了一个月,终于可以点灯。小白自学没办法,都是新知识,卡在一个地方好久都出不来。
UART串口助手接收信息:
发送14(HEX)灭LED
接收电量信息,每次加1,LED亮
发送0A(HEX),LED亮
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland