硬件條件:飛思卡爾的二型集中器(基於Coretex-M4的飛思卡爾K60方案) 其中網卡芯片是AR8032
軟件條件: IAR開發平臺 MQX 系統
首先,創建一個自啓動任務 MQX_AUTO_START_TASK
const TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
/* Task Index, Function, Stack, Priority, Name, Attributes, Param, Time Slice */
{ 1, Main_task, 2000L, 9, "INIT", MQX_AUTO_START_TASK, 0, 0 },
{9, NET_recv_task, 5200L, 10, "NET_recv", 0, 0, 0 },
{10, NET_send_task, 6000L, 10, "NET_send", 0, 0, 0},
{ 0 }
};
這裏要注意分配的棧空間。其中,第四 個參數爲 優先級。越大優先級越低,10比9的優先級小。分配 NET_recv_task 和NET_send_task爲10,讓他們並行。
void Main_task( uint_32 temp)
{
_task_id NET_recv_task_id;
_task_id NET_send_task_id;
queue1 = (CHARQ_STRUCT_PTR)_mem_alloc_system((_mem_size)( sizeof(CHARQ_STRUCT) - (4 * sizeof(char)) + QUEUE_SIZE_1));
_CHARQ_INIT(queue1, QUEUE_SIZE_1);
NET_recv_task_id=_task_create( 0, 9, 0); //創建recv_task
if (NET_recv_task_id == MQX_NULL_TASK_ID) {
printf("\n Could not create NET_recv_task\n");
}
NET_send_task_id=_task_create( 0, 10, 0); //創建send_task
if (NET_send_task_id == MQX_NULL_TASK_ID) {
printf("\n Could not create NET_recv_task\n");
}
}
衆所周知,每個任務體都有個死循環。要想讓其他任務執行。最好在這個循環中有一個阻塞函數。或者用一個延時_time_delay(400); 這個當中的400 ms爲經驗值。
void NET_send_task(uint_32 temp)
{
// 網口檢測 check the internet device linking
//fix me!!!
int i=0;
int j=1;
int send_length=0;
uchar buff4;
uchar buff3[1];
while(1)
{
printf("Andy: FILE %s FUNCTION %s LINE %d j is %d \n",__FILE__,__FUNCTION__,__LINE__,j);
init_NET(0); //初始化網絡,並建立起已經連接的套接字
_time_delay(400); //讓出時間片
printf("Andy: FILE %s FUNCTION %s LINE %d j is %d \n",__FILE__,__FUNCTION__,__LINE__,j);
while(flag)
{
flag=0;
uchar buf[]={0x68,0x32,0x00,0x32,0x00,0x68,0xC9,0x01,0x35,0x01,0x00,0x00,0x02,0x70,0x00,0x00,0x01,0x00,0x73, 0x16};
send_length=send(sockClient,buf,sizeof(buf),0);
printf("Andy: FILE %s FUNCTION %s LINE %d send_length is %d j is %d\n",__FILE__,__FUNCTION__,__LINE__,send_length,j);
}
printf("\nthe sizeof queue is %d \n",_CHARQ_SIZE(queue1));
while( (send_length>0)&(!_CHARQ_EMPTY(queue1)))
{
_CHARQ_DEQUEUE(queue1, buff4);
printf("Andy : FUNCTION %s :the char in queue is %02x\n",__FUNCTION__,buff4);
}
}
}
這裏向服務端發送一個約定好的心跳包。/*
FUCTION: NET_recv_task
comments: 通過以太網接受數據
*/
void NET_recv_task(uint_32 temp)
{
uint_32 i;
_queue_id server_qid;
uchar buf1[1024]={0};
int recv_length;
int send_length;
uchar buff4;
TIME_STRUCT time;
uint_32 End_Time;
uint_32 Start_Time;
_time_get(&time);
End_Time=time.SECONDS*1000 + time.MILLISECONDS;
Start_Time=End_Time;
while(1)
{
while(1==( recv_length=recv(sockClient,buf1,1,0)))
{
if(recv_length>0)
my_printf(buf1,recv_length); // 對接收到的數據進行處理
_CHARQ_ENQUEUE(queue1, buf1[0]);
printf("recv_length is %d the recv data is : \n",recv_length);
}
//一分鐘接收不到任何數據,讓send_task 發送一個心跳包
_time_get(&time);
End_Time=time.SECONDS*1000 + time.MILLISECONDS;
printf(" End_Time is %d, Start_Time is %d\n",End_Time,Start_Time);
if(1==recv_length)
{
Start_Time=End_Time;
}
else
{
if(( End_Time-Start_Time)>60000)
{
printf(" End_Time is %d, Start_Time is %d\n",End_Time,Start_Time);
Start_Time=End_Time;
flag=1;
}
}
_time_delay(400); //讓出時間片
}
}
1.隊列的操作
隊列是MQX 任務之間輕量級的傳遞數據的工具。文檔《Freescale MQX 實時操作系統用戶手冊》中對列的描述如下:
這個隊列在操作系統中,應用很廣泛。個人感覺這QUEUE_STRUCT 主要用設備驅動方面(mqx\source\kernel\Queue.c)。把表示設備的結構體鏈接到內核裏面。不太適合,一個字符進入,一個字符出來的情況。這裏主要使用 CHARQ_STRUCT (mqx\source\include\charq.h)。 值得注意是這個隊列的初始化,並不是在這個頭文件中 _CHARQ_INIT(cq,max_size) 。在申請隊列大小時需要爲它分配空間。
queue1 = (CHARQ_STRUCT_PTR)_mem_alloc_system((_mem_size)( sizeof(CHARQ_STRUCT) - (4 * sizeof(char)) + QUEUE_SIZE_1));
CHARQ_STRUCT 結構體定義如下:
typedef struct charq_struct
{
/*!
* \brief The maximum number of characters for the queue, as specified in
* initialization of the queue.
*/
_mqx_uint MAX_SIZE;
/*! \brief The current number of characters in the queue. */
_mqx_uint CURRENT_SIZE;
/*! \brief Index of the first character in queue. */
_mqx_uint HEAD;
/*! \brief Index of the last character in queue. */
_mqx_uint TAIL;
/*! \brief The character queue itself. */
char QUEUE[4];
} CHARQ_STRUCT, _PTR_ CHARQ_STRUCT_PTR;
申請的結構的在內存中的分佈如下:
2.MQX中的網絡操作
RTCS_create() 通信組件起來之後,ENET_initialize(.....) 初始化網絡之後,在於本機(集中器)的IP綁定。然後常規的TCP客戶端操作即可以聯上。
在ENET_initialize(...)之後,我們會得到一個句柄(ehandle) ,通過( ENET_link_status(ehandle))可以得到這個時候機器的網線插拔狀態。