本人有幸于8月份参与moore8代理TI活动赠送的一套CC3200评估板,一个cc3200核心板集成的FPGA下载器,和一根优质micro usb数据线。拿到评估板通过USB连接到电脑上安装一系列驱动后,研究了近一个月,结合各位大佬的示例,总结一下心得。先说一下cc3200,cc3200是TI公司2014年开发的业界第一款内嵌WIFI核心的SOC级芯片,其中两个核心,一个基于Cotex-M4的应用处理器核和一个WIFI网络处理器核,而且其拥有的256K 外置flash 由两个核共享。
1、本项目使用TI的CCS6.1.0版本的编译器(不同板子对应的开发软件版本可能不同,有时会提示发生版本错误或者组件错误的信息)
2、本项目使用OURS的cc3200 simplelink 物联网研发套件中的核心板和传感器底板
3、本项目使用TI的CCS Uniflash软件烧写bin文件
4、如果刚开始使用CC3200的新手的话,建议使用Pinmux软件配置相应引脚
第一步:配置开发环境
1、本项目采用ccs开发编译环境,大家可以在TI官网或者点击这个链接下载http://processors.wiki.ti.com/index.php/Download_CCS,下载完成后进行安装,具体安装这里就不演示了。2、下面需要注意的是安装完并且成功激活后,还需要去官网下载SDK开发包http://www.ti.com/tool/cc3200sdk,里面有service pack固件包,这个包是联网服务要用的,这个等会再说。
3、然后还需要安装CCS uniflash来烧写bin文件http://www.ti.com/tool/uniflash?keyMatch=uniflash
4、如果是使用cc3200的新手的话,真的建议用pinmux来配置各种参数http://www.ti.com/tool/pinmuxtool,跟STM32Cube有点像。
配置完开发环境,然后就要开始进入CCS6.1.0开发cc3200啦。
第二步:开发CC3200
1、进入CCS主界面以后,在上面选项面板点击Project–>然后选择Import CCS Projects,选择相应位置的文件夹
配置完开发环境,然后就要开始进入CCS6.1.0开发cc3200啦。
第二步:开发CC3200
1、进入CCS主界面以后,在上面选项面板点击Project–>然后选择Import CCS Projects,选择相应位置的文件夹
点击确定之后,就可以看到项目处在候选栏目里啦,然后把文件夹里的本项目所包含的drivelib模块(外设驱动模块),oslib模块(free RTOS系统驱动模块),
simplink网络驱动模块以及Onenet部分(main文件在这个里面)等四个部分选址选上,再点确定,整个项目就被导入进来啦。(如果该文件夹有多个项目的话,在候选栏里是可以选择的,这样很方便)
2、导入项目之后,就可以开发啦,大概开发思路是,先利用TI的Smartconfig配置WIFI为station模式,然后连接AP热点,创建tcp套接字连接云端的HTTP OneNET服务器,利用IIC将sht20的温湿度数据读取出来,存到缓存buff中,然后打包这些数据成json格式,通过OneNET的API将数据发送过去,我把它扔进free RTOS系统里了,系统更稳定,不多说,直接上代码。
static long ConfigureSimpleLinkToDefaultState()
{
SlVersionFull ver = {0};
_WlanRxFilterOperationCommandBuff_t RxFilterIdMask = {0};
unsigned char ucVal = 1;
unsigned char ucConfigOpt = 0;
unsigned char ucConfigLen = 0;
unsigned char ucPower = 0;
long lRetVal = -1;
long lMode = -1;
lMode = sl_Start(0, 0, 0);
ASSERT_ON_ERROR(lMode);
// If the device is not in station-mode, try configuring it in station-mode
if (ROLE_STA != lMode)
{
if (ROLE_AP == lMode)
{
// If the device is in AP mode, we need to wait for this event
// before doing anything
while(!IS_IP_ACQUIRED(g_ulStatus))
{
#ifndef SL_PLATFORM_MULTI_THREADED
_SlN**MainLoopTask();
#endif
}
}
// Switch to STA role and restart
lRetVal = sl_WlanSetMode(ROLE_STA);
ASSERT_ON_ERROR(lRetVal);
lRetVal = sl_Sto**FF);
ASSERT_ON_ERROR(lRetVal);
lRetVal = sl_Start(0, 0, 0);
ASSERT_ON_ERROR(lRetVal);
// Check if the device is in station again
if (ROLE_STA != lRetVal)
{
// We don't want to proceed if the device is not coming up in STA-mode
ASSERT_ON_ERROR(DEVICE_NOT_IN_STATION_MODE);
}
}
// Get the device's version-information
ucConfigOpt = SL_DEVICE_GENERAL_VERSION;
ucConfigLen = sizeof(ver);
lRetVal = sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION, &ucConfigOpt,
&ucConfigLen, (unsigned char *)(&ver));
ASSERT_ON_ERROR(lRetVal);
UART_PRINT("Build Version: %s\n\r",SL_DRIVER_VERSION);
// Set connection policy to Auto + SmartConfig
// (Device's default connection policy)
lRetVal = sl_WlanPolicySet(SL_POLICY_CONNECTION,
SL_CONNECTION_POLICY(1, 0, 0, 0, 1), NULL, 0);
ASSERT_ON_ERROR(lRetVal);
// Remove all profiles
lRetVal = sl_WlanProfileDel(0xFF);
ASSERT_ON_ERROR(lRetVal);
//
// Device in station-mode. Disconnect previous connection if any
// The function returns 0 if 'Disconnected done', ** numbe**lready
// disconnected Wait for 'disconnection' event if 0 is returned, Ignore
// other return-codes
//
lRetVal = sl_WlanDisconnect();
if(0 == lRetVal)
{
// Wait
while(IS_CONNECTED(g_ulStatus))
{
#ifndef SL_PLATFORM_MULTI_THREADED
_SlN**MainLoopTask();
#endif
}
}
// Enable DHCP client
lRetVal = sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE,1,1,&ucVal);
ASSERT_ON_ERROR(lRetVal);
// Disable scan
ucConfigOpt = SL_SCAN_POLICY(0);
lRetVal = sl_WlanPolicySet(SL_POLICY_SCAN , ucConfigOpt, NULL, 0);
ASSERT_ON_ERROR(lRetVal);
// Set Tx power level for station mode
// Number between 0-15, as dB offset from max power – 0 will set max power
ucPower = 0;
lRetVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID,
WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, 1, (unsigned char *)&ucPower);
ASSERT_ON_ERROR(lRetVal);
// Set PM policy to normal
lRetVal = sl_WlanPolicySet(SL_POLICY_PM , SL_NORMAL_POLICY, NULL, 0);
ASSERT_ON_ERROR(lRetVal);
// Unregister mDNS services
lRetVal = sl_NetAppMDNSUnRegisterService(0, 0);
ASSERT_ON_ERROR(lRetVal);
// Remove all 64 filters (8*8)
memset(RxFilterIdMask.FilterIdMask, 0xFF, 8);
lRetVal = sl_WlanRxFilterSet(SL_REMOVE_RX_FILTER, (_u8 *)&RxFilterIdMask,
sizeof(_WlanRxFilterOperationCommandBuff_t));
ASSERT_ON_ERROR(lRetVal);
lRetVal = sl_Stop(SL_STOP_TIMEOUT);
ASSERT_ON_ERROR(lRetVal);
InitializeAppVariables();
return lRetVal; // Success
}
以上这段代码是将WIFI配置成Station模式,SmartConfig驱动已经在底层实现了,只需简单的几步就可以了。
********************************************************************************************************
//设置sta模式并连接到网络
//返回0 ,连接成功
//返回-1,连接失败
//在common.h文件里面配置热点名字SSID_NAME和热点密码SECURITY_KEY
static signed char scNetStaInit(void) {
SlSecParams_t secParams = {0};
long lRetVal = -1;
//主要是设置成默认的状态,这个在httpserver就有了
lRetVal = ConfigureSimpleLinkToDefaultState();
if(lRetVal < 0)
{
if (DEVICE_NOT_IN_STATION_MODE == lRetVal)
UART_PRINT("Failed to configure the device in its default state\n\r");
LOOP_FOREVER();
}
//需要先调用这个
lRetVal = sl_Start(0, 0, 0);
if (lRetVal < 0)
{
UART_PRINT("Failed to start the device \n\r");
LOOP_FOREVER();
}
// staring simplelink
g_uiSimplelinkRole = sl_Start(NULL,NULL,NULL);
// 设置成sta模式
if(g_uiSimplelinkRole != ROLE_STA )
{
//Switch to STA Mode
lRetVal = sl_WlanSetMode(ROLE_STA);
ASSERT_ON_ERROR(lRetVal);
lRetVal = sl_Stop(SL_STOP_TIMEOUT);
g_usMCNetworkUstate = 0;
g_uiSimplelinkRole = sl_Start(NULL,NULL,NULL);
}
//密码
secParams.Key = (signed char*)SECURITY_KEY;
//密码长度
secParams.KeyLen = strlen(SECURITY_KEY);
//加密类型
secParams.Type = SECURITY_TYPE;
//进行连接,参数有 SSID ,密码
lRetVal = sl_WlanConnect((signed char*)SSID_NAME, strlen(SSID_NAME), 0, &secParams, 0);
ASSERT_ON_ERROR(lRetVal);
//判断有没有连接成功。其实就是判断g_ulStatus响应的位有没有设置成功
//g_ulStatus的值在SimpleLinkWlanEventHandler这个函数内被更改
//SimpleLinkWlanEventHandler是一个回调函数,主要的就是作用就是
//当CC3200连上网络或者断开网络的时候会被调用
while((!IS_CONNECTED(g_ulStatus)) || (!IS_IP_ACQUIRED(g_ulStatus)))
{
//进行循环,等待成功
}
return 0;
}
上面这段代码先是判断WIFI有没有处于Station模式,没有的话就转到Station模式,然后,利用Simplelink连接AP热点连上网络,AP热点在common.h里配置,代码链接在文末贴出来。
**********************************************************************************
//这个函数是我从nerwork_if文件拷贝出来的.不能直接包含那个文件
//因为会引起重复定义的错误。
long Network_IF_GetHostIP( char* pcHostName,unsigned long * pDestinationIP )
{
long lStatus = 0;
lStatus = sl_NetAppDnsGetHostByName((signed char *) pcHostName,
strlen(pcHostName),
pDestinationIP, SL_AF_INET);
ASSERT_ON_ERROR(lStatus);
UART_PRINT("Get Host IP succeeded.\n\rHost: %s IP: %d.%d.%d.%d \n\r\n\r",
pcHostName, SL_IPV4_BYTE(*pDestinationIP,3),
SL_IPV4_BYTE(*pDestinationIP,2),
SL_IPV4_BYTE(*pDestinationIP,1),
SL_IPV4_BYTE(*pDestinationIP,0));
return lStatus;
}
unsigned long GetOnenetIp(void) {
unsigned long ip;
signed int retval;
retval = Network_IF_GetHostIP(Onenet_Site,&ip);
if (retval < 0) {
return 0;
} else {
return ip;
}
}
上面这两个函数就是DNS解析函数啦,如果不知道http Onenet的IP地址,没关系,知道域名之后,可以通过这两个函数把云服务器的IP解析出来。如果你知道IP地址,也可以在前面的宏定义中把IP地址定义出来,http超文本传输的端口号是80。
***********************************************************************************************
char g_buffer[300];
//发送数据给指定的ip和端口号,只有一次
//执行过程
//1、新建连接
//2、发送数据、
//3、断开连接
void vSendOneDataWithIpPort(char *data,long len,long ip,long port) {
SlSockAddrIn_t sAddr;
int iAddrSize;
int iSockID;
int iStatus;
int size;
//** the TCP server socket address
//使用的是socket
//这个我忘了,基本是固定不变
**in_family = SL_AF_INET;
//端口信息,
**in_port = sl_Ht**((unsigned short)port);
//ip信息
**in_addr.s_addr = sl_Htonl((unsigned int)ip);
iAddrSize = sizeof(SlSockAddrIn_t);
// creating a TCP socket
//创建一个tcp连接
iSockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
if( iSockID < 0 )
{
UART_PRINT("Error:%s %d\r\n",__FUNCTION__,__LINE__);
}
// connecting to TCP server
//连接到tcp的服务器,参数:socket的句柄,目的地址信息
iStatus = sl_Connect(iSockID, ( SlSockAddr_t *)&sAddr, iAddrSize);
if( iStatus < 0 )
{
// error
iStatus = sl_Close(iSockID);
if (iStatus < 0)
UART_PRINT("Error:%s %d\r\n",__FUNCTION__,__LINE__);
}
//连接完成最好不要直接就发送数据,经我的测试是,马上发送数据可能会成功,但是数据却没有传过去
delay_ms(100);
//发送数据,参数:socket的句柄,数据指针,数据长度,最后一个参数没有作用
iStatus = sl_Send(iSockID, data, len, 0 );
if( iStatus <= 0 )
{
// error
iStatus = sl_Close(iSockID);
if (iStatus < 0)
UART_PRINT("Error:%s %d\r\n",__FUNCTION__,__LINE__);
}
//接收数据。参数:socket的句柄,缓冲区,缓冲器大小,返回的是接收的数据大小
//请注意这个函数可能是阻塞的
//阻塞的意思就是,会一直等到有数据才返回,或者有问题才返回
size = sl_Recv(iSockID,g_buffer,300,0);
g_buffer[size] = 0;
UART_PRINT("\r\nReceive:\r\n%s\r\n",g_buffer);
//关闭连接
iStatus = sl_Close(iSockID);
if (iStatus < 0)
UART_PRINT("Error:%s %d\r\n",__FUNCTION__,__LINE__);
}
上面这个函数就是拼接IP和端口组成套接字,然后创建tcp连接,然后将POST的json数据报和传感器得到的温湿度数据存到buff中,待连上tcp OneNET服务器的时候再把buff中数据再发送过去。
******************************************************************************
//http的post数据格式
char PostData[] ="POST /devices/%d/datap**?type=3 HTTP/1.1\r\n"
"Host:api.heclouds.com\r\n"
"api-key: %s \r\n"
"Content-Length: %d \r\n"
"\r\n"
"%s";
static void OnenetTask(void *pvParameters) {
unsigned long ip;
char buffer[40];
scNetStaInit();
delay_ms(100);
UART_PRINT("success:%s %d\r\n",__FUNCTION__,__LINE__);
while(1) {
ip = GetOnenetIp();
if (ip != 0) {
//这个主要就是发送JSON的数据
GPIO_IF_LedOn(MCU_GREEN_LED_GPIO);
delay_ms(100);
GPIO_IF_LedOff(MCU_GREEN_LED_GPIO);
IIC_Init();
SHT20_GetValue();
snprintf(buffer,40,"{\"Temperature\":%.2f,\"Humidity\":%.2f}\r\n",sht20Info.tempreture,sht20Info.humidity);
snprintf(g_buffer,190,PostData,Device_ID,API_Key,strlen(buffer),buffer);
UART_PRINT("Send:\r\n%s\r\n",g_buffer);
//发送数据,参数:数据,数据长度,IP地址,端口
vSendOneDataWithIpPort(g_buffer,strlen(g_buffer),ip,Onenet_Port);
delay_ms(50000); //整个过程大概1分钟传一次数据
}
delay_ms(100);
}
}
上面就是创建了一个连接OneNET云平台的task,每次在获取到IP地址即连上网之后,才去初始化IIC以及读取sht20的数据,避免了万一没连上网但是却不断在发送数据的情况,vSendOneDataWithIpPort就是创建了套接字然后发送数据,这也是合成http协议的过程。
第三步:调试仿真
在程序完成后,需要将整个项目的四个文件夹一起run,编译完整个项目后,在左侧的Project Explore里面,右键包含main文件的文件夹,
然后点击new,创建一个target configure file,选择stellaris in-circuit debug inte**ce选项,勾选上cc3200(确保电脑可以识别你的cc3200板子,
装好相应驱动,这方面资料很多),然后点击save,最后点击菜单栏上绿色的小虫子那个图标就可以进入调试仿真模式啦。
第四步:烧写程序到cc3200
打开Uniflash,新建New Target Configuration,然后选择cc3x serial(UART) inte**ce,点ok就可以啦。然后就开始倒腾硬件啦,将芯片上的SOP2接一个限流电阻连接至vcc,很多开发板都有跳线或者开关的,然后看一下cc3200在电脑上的串口号,填好之后format一下,建议Capacity选择8M。
接着进入/sys/mcuimg.bin板块开始配置烧写设置,全选上Erase,Update和Verify,取消Rollback,在Url处找到你编译好的项目的bin文件,在release文件夹里面。选好之后就开始点击菜单栏的Operation—>Program,可能中途还有让你Reset的提示,按提示做就好了。烧写完之后,进入flash setup and control面板,点击service pack programming,选择安装好的SDK里面的service pack 开发包,烧写完之后,将SOP2接至GND,就可以将cc3200里面的程序运行出来了。最后的运行情况如图。本文参考链接:open.iot.10086.cn/…/forum.php
user5324490:
谢谢分享,最近也在玩ONENET,支持一下
user5324490:
楼主的代码很完整啊,一看就是高手,期待后续更多的项目分享
user3687004:
这个评测的步骤很详细,调试仿真有无经验可循,最后测量温度的结果最好能界面化显示。
user5367733:
代码都贴出来了,以后有机会一定得烧进去试试,感谢楼主分享!
user6155536:
分享的很详细,测试代码也粘贴出来,学习学习
user3883604:
代码完整工整,很有帮助,对照调试一下
user6131345:
厉害了,厉害了,这个分享可以的
user6055773:
对板载程序二次开发中又遇到什么难题没?
user5317170:
期待更多开发项目代码分享!加油!