本次体验的功能比较简单,将开发板上电,然后打开手机蓝牙,搜索并连接上“MindMotion-Shutter”蓝牙设备,然后打开手机的照相机,放在离开发板有一定距离的地方,然后通过按下按键K4来抓拍美丽的瞬间。主要的几个源文件与调用函数简单的罗列一下:
#include "sys.h"#include "delay.h" #include "uart.h" #include "spi.h" #include "RF_IRQ.h" #include <string.h> #include "HAL_conf.h" #include "mg_api.h" #include "mg_test_api.h" #include "iwdg.h" #include "RF_Callback.h" extern void Key_Shutter_Init(void); unsigned char *ble_mac_addr; u8 value_t[2]; unsigned char *get_local_addr(void) //used for ble pairing case { return ble_mac_addr; } void BLE_SV() { unsigned char *BLE_SV = get_ble_version(); } u8 ADV_Data[] = {'T', 'E', 'S', 'T'}; unsigned long i; int main(void) { unsigned long temp = 0x800000; while (temp--); SPIM_Init(0x06); IRQ_RF(); SYSTick_Configuration(); uart_initwBaudRate(); SetBleIntRunningMode(); radio_initBle(TXPWR_3DBM, &ble_mac_addr); IWDG_Init(4, 625); Key_Shutter_Init(); value_t[0] = 0xc0; value_t[1] = *(u8 *)0x1FFFF820; //Read FT value(FT value:The RF module is calibrated at the factory to prevent frequency deviation. The user can call the FT value in the program) ble_run_interrupt_start(80); //320*0.625=200 ms while (1) { } }
复制代码#ifndef _MG_API_H_#define _MG_API_H_ //TX power #define TXPWR_3DBM 0x48 #define TXPWR_0DBM 0x43 #define TXPWR__3DBM 64 #define TXPWR__6DBM 61 #define TXPWR__8DBM 58 #define TXPWR__15DBM 48 // ATT Error Codes #define ATT_ERR_INVALID_HANDLE 0x01 #define ATT_ERR_READ_NOT_PERMITTED 0x02 #define ATT_ERR_WRITE_NOT_PERMITTED 0x03 #define ATT_ERR_INVALID_PDU 0x04 #define ATT_ERR_INSUFFICIENT_AUTHEN 0x05 #define ATT_ERR_UNSUPPORTED_REQ 0x06 #define ATT_ERR_INVALID_OFFSET 0x07 #define ATT_ERR_INSUFFICIENT_AUTHOR 0x08 #define ATT_ERR_PREPARE_QUEUE_FULL 0x09 #define ATT_ERR_ATTR_NOT_FOUND 0x0a #define ATT_ERR_ATTR_NOT_LONG 0x0b #define ATT_ERR_INSUFFICIENT_KEY_SIZE 0x0c #define ATT_ERR_INVALID_VALUE_SIZE 0x0d #define ATT_ERR_UNLIKELY 0x0e #define ATT_ERR_INSUFFICIENT_ENCRYPT 0x0f #define ATT_ERR_UNSUPPORTED_GRP_TYPE 0x10 #define ATT_ERR_INSUFFICIENT_RESOURCES 0x11 //adv header type #define ADV_HDR_TYPE_PUBLIC_IND 0x00 #define ADV_HDR_TYPE_RANDOM_IND 0x80 #define ADV_HDR_TYPE_PUBLIC_NONCONN_IND 0x02 #define ADV_HDR_TYPE_RANDOM_NONCONN_IND 0x82 //Function: radio_initBle //Parameters: txpwr - input, txpower; addr - output, BLE device address //return: None void radio_initBle(unsigned char txpwr, unsigned char** addr/*out*/); //init ble mode, should be called first after spi initialization //Function: radio_initBle_TO //Parameters: txpwr - input, txpower; addr - output, BLE device address; ms_timeout - timeout for BLE initialization, recommend value 10~50 //return: 0 - fail; none 0 - success unsigned char radio_initBle_TO(unsigned char txpwr, unsigned char** addr, unsigned short ms_timeout); //Function: radio_initBle_recover //Parameters: txpwr - input, txpower; addr - output, BLE device address //return: None void radio_initBle_recover(unsigned char txpwr, unsigned char** addr); //Function: radio_setCal_nonBlocking //Parameters: nonblocking - 0: blocking; 1: non blocking //return: none void radio_setCal_nonBlocking(unsigned nonblocking); //Function: radio_standby //this function is to set rf to standby mode, I ~ 3uA //Parameters: none //return: None //called in UsrProcCallback or when ble_run_interrupt_McuCanSleep()>0 void radio_standby(void); //Function: radio_resume //this function is to recover rf from standby mode //Parameters: none //return: None void radio_resume(void); //Function: radio_setXtal //this function is to config the params of xtal //Parameters: xoib:0~f, xocc:0 //return: None void radio_setXtal(unsigned char xoib, unsigned char xocc); //Function: radio_setRxGain //this function is to config the params of RX //Parameters: lna_gain:0,5,6,7, preambe_th: 0x20 when lna_gain=0, 0x38 when lna_gain=5,6,7 //return: 0-input param error, 1-ok unsigned char radio_setRxGain(unsigned char lna_gain, unsigned char preamble_th); //Function: ble_run //Parameters: interv_adv - advertise packet interval, unit 0.625ms //return: None //Remarks: never reurn!!! void ble_run(unsigned short interv_adv); //Function: ble_set_adv_data //Parameters: adv - advertise packet payload; len - payload len //return: None void ble_set_adv_data(unsigned char* adv, unsigned char len); //Function: ble_set_adv_rsp_data //Parameters: rsp - advertise response payload; len - payload len //return: None void ble_set_adv_rsp_data(unsigned char* rsp, unsigned char len); //Function: ble_set_name //this function IS available when using default scan response data //Parameters: name - device name; len - name len //return: None void ble_set_name(unsigned char* name,unsigned char len); //Function: ble_set_adv_type //Parameters: type - advertisement type, 0-adv_ind, 2-adv_nonconn_ind. default 0x80 // addr type, 0x80 - RANDOM, 0x00 - PUBLIC //return: None void ble_set_adv_type(unsigned char type); //Function: ble_set_interval //Parameters: interval - advertisement interval, unit 0.625ms //return: None void ble_set_interval(unsigned short interval); //Function: ble_set_wakeupdly //Parameters: counter - wake up delay time, unit 16uS //return: 1 unsigned char ble_set_wakeupdly(unsigned short counter); //Function: ble_set_adv_enableFlag //this function is to enable/disable ble adv //Parameters: sEnableFlag - 0 to disable adv, 1 to enable adv //return: None void ble_set_adv_enableFlag(char sEnableFlag); //Function: ble_set_role //this function is to set ble role to peripheral(0) or central(1), by default ble role is peripheral(0) //Parameters: role_new - 0 peripheral, 1 central // scan_window - scan window for central rol. range: 0x0004~0x4000 (2.5ms ~ 10.24s) //return: 0 - fail, 1 - success unsigned char ble_set_role(unsigned char role_new, unsigned short scan_window); //Function: ble_disconnect //this function is to disconnected the ble connection //Parameters: none //return: None void ble_disconnect(void); unsigned char* GetFirmwareInfo(void); //such as "FVxx.2.0.2mmx" unsigned char* get_ble_version(void); //such as "MG_BLE_LIB_V1.0" unsigned char GetRssiData(void); //only valid after receive a packet void att_notFd(unsigned char pdu_type, unsigned char attOpcode, unsigned short attHd ); void att_ErrorFd_eCode(unsigned char pdu_type, unsigned char attOpcode, unsigned short attHd, unsigned char errorCode); void att_server_rdByGrTypeRspDeviceInfo(unsigned char pdu_type); void att_server_rdByGrTypeRspPrimaryService(unsigned char pdu_type, unsigned short start_hd, unsigned short end_hd, unsigned char*uuid, unsigned char uuidlen); void att_server_rd( unsigned char pdu_type, unsigned char attOpcode, unsigned short att_hd, unsigned char* attValue, unsigned char datalen ); void ser_write_rsp_pkt(unsigned char pdu_type); unsigned char sconn_notifydata(unsigned char* data, unsigned char len);//returns data size has been sent, ******* user's safe API ********* unsigned char sconn_indicationdata(unsigned char* data, unsigned char len);
复制代码void SIG_ConnParaUpdateReq(unsigned short IntervalMin, unsigned short IntervalMax, unsigned short slaveLatency, unsigned short TimeoutMultiplier);unsigned short sconn_GetConnInterval(void);//get current used interval in the unit of 1.25ms //Get current (or the latest) connected master device's MAC //returns mac(6 Bytes, Little-Endian format) and the type(MacType, 0 means public type, others mean random type) unsigned char* GetMasterDeviceMac(unsigned char* MacType); //PAIR APIs void SetLePinCode(unsigned char *PinCode/*6 0~9 digitals*/); //Get current connected device's long term KEY's info(EDIV) //returns u8* EDivData /*2 Bytes*/ (encrypted) //newFlag: 1 means new paired device's info, 0 means old paired device's info. //Remarks: // 1. This function shall be invoked when [StartEncryption == 1]. // 2. This function is ONLY supported in pairing cases. unsigned char* GetLTKInfo(unsigned char* newFlag); //security manager module request for pair //Remarks: // 1. This function shall be invoked when [connected status == 1]. // 2. This function is ONLY supported in pairing cases. void s_llSmSecurityReq(void); //return: // OTA_OK 0 // OTA_SN_ERROR 1 // OTA_CHECKSUM_ERROR 2 // OTA_FORMAT_ERROR 3 // OTA_UNKNOWN_ERROR 255 unsigned char OTA_Proc(unsigned char *data, unsigned short len); //interrupt running mode APIs //Function: SetBleIntRunningMode //this function SHOULD be invoked before init the ble //Parameters: None //return: None void SetBleIntRunningMode(void); //Function: ble_run_interrupt_start // this function SHOULD be invoked to start the interrupt running mode in the main routine. // ble_run(0) function SHOULD ONLY be invoked in the ble irq interrupt service subroutine. //Parameters: interv_adv - advertise packet interval, unit 0.625ms //return: None void ble_run_interrupt_start(unsigned short interv_adv); //Function: ble_nMsRoutine //this function SHOULD be invoked every 1ms tick, one can invoke this function inside the systick routine //Parameters: None //return: None void ble_nMsRoutine(void); //Function: ble_run_interrupt_McuCanSleep //this function CAN be invoked at main task, one can invoke this function to detect the BLE status then goto MCU sleep. //Before doing so, one SHOULD configure the BLE irq down wakeup pin's function enabled. //Parameters: None //return: None-zero means MCU can enter into stop/sleep mode. unsigned char ble_run_interrupt_McuCanSleep(void); //debug APIs //Parameters: isFixCh37Flag - input, 1-adv on ch37 only, 0-adv on ch37,38,39. default:0 void SetFixAdvChannel(unsigned char isFixCh37Flag);
复制代码//function listAT_CMD_FUNC at_func_list[] = { {atcmd_SetName, "SETNAME="}, {atcmd_SetAdvInt, "SETINTERVAL="}, {atcmd_SendData, "BLESEND="}, {atcmd_LowPower, "LOWPOWER="}, {atcmd_SetBaud, "SETBAUD="}, {atcmd_SetAdvFlag, "SETADVFLAG="}, {atcmd_DisconnecteBle, "DISCON"}, {atcmd_Minfo, "MINFO"}, {atcmd_Help, "HELP"}, };
复制代码控制模块系统时钟的选择是在启动时进行,复位时内部48MHz的振荡器被选为默认的CPU时钟,随后可以选择外部的16MHz时钟;当检测到外部时钟失效时,它将被隔离,系统将自动地切换到内部的振荡器,如果使能了中断,软件可以接收到相应的中断。同样,在需要时可以采取对PLL时钟完全的中断管理(如当一个间接使用的外部振荡器失效时)。多个预分频器用于配置AHB的频率、高速APB(APB2和APB1)区域,AHB和高速APB的最高频率是96MHz。时钟树如下图所示:

蓝牙ATT服务特征值在“app_hogp.c”文件中添加,包括以小端模式存储的128位uuid。
const BLE_CHAR AttCharList[] = {// ====== gatt ===== Do NOT Change!! {TYPE_CHAR,0x03,ATT_CHAR_PROP_RD, 0x04,0,0x00,0x2a,UUID16_FORMAT},//name //05-06 reserved // ====== device info ===== Do NOT Change if using the default!!! {TYPE_CHAR,0x08,ATT_CHAR_PROP_RD, 0x09,0,0x29,0x2a,UUID16_FORMAT},//manufacture {TYPE_CHAR,0x0a,ATT_CHAR_PROP_RD, 0x0b,0,0x26,0x2a,UUID16_FORMAT},//firmware version {TYPE_CHAR,0x0c,ATT_CHAR_PROP_RD, 0x0d,0,0x50,0x2a,UUID16_FORMAT},//PnPID {TYPE_CHAR,0x0e,ATT_CHAR_PROP_RD, 0x0f,0,0x28,0x2a,UUID16_FORMAT},//sw version // ====== HID ===== // {TYPE_INC, 0x1a,},//include, hard code!!! {TYPE_INC, 0x001a,0x2b,0x00, 0x2d,0x00, 0x0a,0xa0}, //hard code uuid-0aa0, I just share the memory {TYPE_CHAR,0x1B,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W_NORSP,0x1c,0, 0x4e,0x2a,UUID16_FORMAT},//protocol mode {TYPE_CHAR,0x1d,ATT_CHAR_PROP_W|ATT_CHAR_PROP_RD|ATT_CHAR_PROP_NTF, 0x1e,0,0x4d,0x2a,UUID16_FORMAT},//report {TYPE_CFG, 0x1f,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W},//cfg {TYPE_RpRef,0x20,ATT_CHAR_PROP_RD},//Report Reference {TYPE_CHAR,0x21,ATT_CHAR_PROP_RD, 0x22,0,0x4b,0x2a,UUID16_FORMAT},//report map {TYPE_xRpRef,0x23,ATT_CHAR_PROP_RD},//External Report Reference {TYPE_CHAR,0x24,ATT_CHAR_PROP_W|ATT_CHAR_PROP_RD|ATT_CHAR_PROP_NTF,0x25,0,0x33,0x2a,UUID16_FORMAT},//boot mouse input report {TYPE_CFG, 0x26,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W},//cfg {TYPE_CHAR,0x27,ATT_CHAR_PROP_RD, 0x28,0,0x4a,0x2a,UUID16_FORMAT},//hid info {TYPE_CHAR,0x29,ATT_CHAR_PROP_W_NORSP, 0x2a,0,0x4c,0x2a,UUID16_FORMAT},//hid control point // ====== 0xa00a ====== include uuid {TYPE_CHAR,0x2c,ATT_CHAR_PROP_RD, 0x2d,0,0x0b,0x0a,UUID16_FORMAT},// // ====== battery service ====== {TYPE_CHAR,0x2f,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_NTF, 0x30,0,0x19,0x29,UUID16_FORMAT},//battery level {TYPE_CFG, 0x31,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W},//cfg // ====== scan prameter service ====== {TYPE_CHAR,0x33,ATT_CHAR_PROP_W_NORSP, 0x34,0,0x4f,0x2a,UUID16_FORMAT},//Scan Interval Window {TYPE_CHAR,0x35,ATT_CHAR_PROP_NTF, 0x36,0,0x31,0x2a,UUID16_FORMAT},//Scan Refresh {TYPE_CFG, 0x37,ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W},//cfg };
复制代码const u8 Hid_map[]= { //first Id 0x05, 0x01, //standard keyboard Usage Page(global)Generic Desktop Controls 0x09, 0x06, //Usage (local) Keyboard 0xA1, 0x01, //collection((Application) 0x85, 0x01, //report ID 0x05, 0x07, //Keyboard/Keypad 0x19, 0xE0, //Usage Minimum 0x29, 0xE7, //Usage Maximum 0x15, 0, //Logical Minimum 0x25, 1, //Logical Maximum 0x75, 1, //Report Size(1 bit) 0x95, 8, //Report Count(8) 0x81, 2, //input(2) - variable absolute data 0x95, 1, //Report Count(1) 0x75, 0x08, //Report Size(8 bit) 0x81, 3, //input(3) - variable absolute constant, for OEM data usage 0x95, 5, //Report Count(5) 0x75, 1, //Report Size(1 bit) 5, 8, //Usage Page(global)LED 0x19, 1, //Usage Minimum 0x29, 5, //Usage Maximum 0x91, 2, //output(2) - variable absolute data 0x95, 1, //Report Count(1) 0x75, 3, //Report Size(3 bit) 0x91, 3, //output(3) - variable absolute constant 0x95, 6, //Report Count(6) 0x75, 8, //Report Size(8 bit) 0x15, 0, //Logical Minimum 0x25, 0xff, //Logical Maximum 5, 7, //Keyboard/Keypad 0x19, 0, //Usage Minimum 0x29, 0xff, //Usage Maximum 0x81, 0, //input(0) - array absolute data 0xc0, //END collection // Second ID 0x05, 0x0c, //Consumer 0x09, 0x01, //Consumer Control 0xA1, 0x01, //collection 0x85, 0x02,//report ID 0x15, 0x00,//Logical Minimum 0x25, 0x01,//Logical Maximum 0x75, 0x01,//Report Size(1 bit) 0x95, 0x1e,//Report Count(30) //first item start 0x09, 0x30, //power 0x09, 0xb0, //play 0x09, 0xb1, //pause 0x09, 0xb2, //record 0x09, 0xb3, //FF 0x09, 0xb4, //FB 0x09, 0xb5, //next 0x09, 0xb6, //pre 0x09, 0xb8, //reject 0x09, 0xb9, //random play 0x09, 0xe2, //Mute 0x09, 0xe9, //V+ 0x09, 0xea, //V- 0x09, 0x95, //help 0x0a, 0x24, 0x02, //AC back 0x0a, 0x25, 0x02, //AC forward 0x0a, 0x26, 0x02, //AC stop 0x0a, 0x27, 0x02, //AC refresh 0x0a, 0x21, 0x02, //AC search 0x0a, 0x2a, 0x02, //AC bookmarks 0x0a, 0x23, 0x02, //AC Home 0x0a, 0x8a, 0x01, //AL email reader 0x0a, 0x83, 0x01, //AL consumer Contrl Configuration 0x0a, 0x94, 0x01, //AL browser 0x0a, 0x92, 0x01, //AL calculater 0x0a, 0x09, 0x02, //AC property 0x0a, 0x7f, 0x02, //AC view clock 0x0a, 0x33, 0x02, //scroll up 0x0a, 0x34, 0x02, //scroll down 0x0a, 0x1F, 0x02, //AC Find //end 0x81, 0x02, //input(2) - variable absolute data 0x95, 0x01, //Report Count(30) 0x75, 0x02, //Report Size(2 bit) 0x81, 0x03, //input(3) - variable absolute constant 0xc0, //end collection };
复制代码/*************************************************************************function: NotifyApplePhoto **@brief This function is apple photo hid photo capture, hard code ** **@param None. ** **@return ************************************************************************/ u8 NotifyApplePhoto(void)//apple photo hid photo capture, hard code { u8 Keyarray[5] = {2,0,8,0,0}; //VolUp,hard code sconn_notifydata(Keyarray,5); Keyarray[2] = 0; sconn_notifydata(Keyarray,5); return 1; } /******************************************************************* **function: NotifyKey **@brief This function is hid standard keyboard key, hardcode ** **@param KeyIdx ** **@return None. ********************************************************************/ u8 NotifyKey(u8 KeyIdx)//hid standard keyboard key, hardcode { u8 Keyarray[9] = {1,0,0,0,0,0,0,0,0};//0xa1 Keyarray[3] = KeyIdx; sconn_notifydata(Keyarray,9); Keyarray[3] = 0; sconn_notifydata(Keyarray,9); return 1; } /*************************************************************** **function: gatt_user_send_notify_data_callback **@brief This callback function can be used to actively send data to the Bluetooth module ** The protocol stack will callback (asynchronously) this function when the system allows it. It must not block! !! **@param None. ** **@return None. ****************************************************************/ void gatt_user_send_notify_data_callback(void) { if(key_shutter==TRUE) { key_shutter=FALSE; NotifyKey(0x28); NotifyApplePhoto(); } }
复制代码
工程编译完成后下载,自动重启

然后打开手机蓝牙,搜索到“MindMotion-Shutter”,并建立连接

接着打开手机的相机应用,放在距离开发板10米以内的地方,此时再通过按下开发板中的K4键,即能完成拍照功能。

此次分享就到这里,后续再扩展其它功能啦,感谢各位网友来访,谢谢上海灵动微电子的赞助,面包社区提供的平台。
