STM32通過廣和通L610進行TCP/IP通信
一、 寫在前面
??本次參加嵌入式大賽,使用了廣和通的ADP-L610-Arduino板子進行通信,專案要求大概是本地上傳資料到服務器,服務器接收后發送給客戶端,實作資料的傳輸,在這個專案中需要用到兩個客戶端,所以需要實作服務端的多執行緒操作,多執行緒我具體還沒整明白,這篇文章介紹的還是單執行緒,TCP/IP通信協議的可靠性、可操作性、安全性等幾個特征,正好是我這次專案所需要的,前前后后整了兩天,寫下這篇博客,分享下經驗的同時也為自己寫下備忘錄,
二、材料準備
- STM32開發板
- ADP-L610-Arduino板子
- 公網IP
【注意】:實際上不限于STM32開發板,只要能進行串口通信的板子就行,運營商通常不會提供靜態公網IP,所以需要我們購買一個服務器,下面會提供阿里云ECS云服務器的簡單使用方法,
三、CS架構TCP/IP通信
??Socket在應用層和傳輸層之間的一個抽象層,它把 TCP/IP 層復雜的操作抽象為幾個簡單的介面,供應用層呼叫實作行程在網路中的通信,Socket 起源于 UNIX,在 UNIX 一切皆檔案的思想下,行程間通信就被冠名為檔案描述符,Socket 保證了不同計算機之間的通信,也就是網路通信,對于網站,通信模型是服務器與客戶端之間的通信,兩端都建立了一個 Socket 物件,然后通過 Socket 物件對資料進行傳輸,通常服務器處于一個無限回圈,等待客戶端的連接,
??本示例代碼的頭檔案是linux平臺的,可以讓服務端回圈等待客戶端連接,但目前僅支持單執行緒連接,多執行緒連接等我用上了會更新,
1.服務端server.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#define PORT 8088 /*埠號*/
#define BACKLOG 1 /*最大監聽數*/
int main(){
int sockfd,new_fd; /*socket句柄和建立連接后的句柄*/
struct sockaddr_in my_addr; /*本方地址資訊結構體,下面有具體的屬性賦值*/
struct sockaddr_in their_addr; /*對方地址資訊*/
int sin_size;
int client;
sockfd=socket(AF_INET,SOCK_STREAM,0); //建立socket
if(sockfd==-1){
printf("socket failed:%d",errno);
return -1;
}
my_addr.sin_family=AF_INET; /*該屬性表示接收本機或其他機器傳輸*/
my_addr.sin_port=htons(PORT); /*埠號*/
my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /*IP,括號內容表示本機IP*/
bzero(&(my_addr.sin_zero),8); /*將其他屬性置0*/
if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))<0){
//系結地址結構體和socket
printf("bind error");
return -1;
}
listen(sockfd,BACKLOG); //開啟監聽 ,第二個引數是最大監聽數
char recvbuf[100];
char sendbuf[]="[\tServer]:server is recieved!";
while(1){
printf("[\tServer]:waitting for connecting\n");
client = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size);
if(client < 0){
printf("[\tClient]:connect fail!\n");
continue;
}
else{
printf("[\tServer]:**********************************\n");
printf("[\tServer]:connect success!port:%d\n",PORT);
}
printf("[\tServer]:waitting for messege....\n");
while(1){
int DataNum = recv(client,recvbuf,100,0);
recvbuf[DataNum]='\0';
if(strcmp(recvbuf,"exit") == 0) break;
if(strcmp(recvbuf,"systemexit") == 0) return 0;
printf("[\tRecv]:%s\n",recvbuf);
send(client,sendbuf,strlen(sendbuf),0);
}
printf("[\tClient]:client exit\n\n\n");
}
close(sockfd);
return 0;
}
2.客戶端
??通過ADP-L610-Arduino的TCP服務來連接,
四、服務器環境搭建
1.進入阿里云官網,點擊產品->熱門產品->云服務器ECS,隨便買一個服務器,

2.進入控制臺里的安全組

3.點擊創建規則,自定義埠的值需要與服務端server.c中的埠號宏定義相同,

4.通過FileZilla將服務器程式server.c發送到服務器上,并在服務器上運行該程式,

四、開發板配置
1.將MCU和ADP-L610-Arduino的串口收發連接上,給兩個開發版供電,

2.使用STM32CubeMX配置連接好的針腳,本示例中,USART1是與L610連接的串口,USART3是stlink的串口,二者的配置引數相同,
????
??
????
3.匯出工程檔案后,通過keil進行編輯,
??3.1進入usart.c中,添加以下代碼,
#include <stdio.h>
int fputc(int ch,FILE *f) /*重映射printf為串口1(MCU與L610之間)發送*/
{
uint8_t temp=ch;
HAL_UART_Transmit(&huart1,&temp,1,2);
return temp;
}
??3.2在main.c中添加以下代碼,
void Creat_TCP(void) /*創建tcp連接*/
{
HAL_Delay(3000);
/*通過串口1向L610發送該指令進行TCP連接*/
printf("AT+MIPOPEN=1,,\"139.196.82.153\",8088,0\r\n");
HAL_Delay(3000);
}
void Send_Data(char *bufferdata) /*發送資料*/
{
HAL_Delay(2000);
printf("AT+MIPSEND=1,13\r\n"); /*通知L610即將發送定長資料,長度為13*/
printf( "%s",bufferdata); /*資料內容*/
HAL_Delay(2000);
}
int i;
Creat_TCP();
for(i=0;i<5;i++){
Send_Data(senddata);
HAL_Delay(1000);
}
4.將程式燒寫進MCU并運行即可完成功能,
五、注意事項
??我是根據官方說明檔案整理出來的,把一些對開發板啟動后的初始化、檢測都去除了,可以說非常精簡,但是簡單的同時也可能會出現錯誤,這個代碼沒有列印log資訊的功能,因此運行程式時如果出錯就挺麻煩,建議用到TCP的朋友還是好好寫一個列印log的功能吧,可以用USART3做,
??這個示例只是大致講了下L610連接TCP服務器的步驟,我也是廢了一定的功夫才整好的,如果有幫到你的話,請點個贊喲,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/287227.html
標籤:其他
