由於對wifi模塊的控制需要,在網上找了許多資料,發現wifi模塊通過單片機進行通訊的代碼不多,也有一些存在着錯誤,於是便自己寫了一個wifi控制舵機和燈的程序,記錄下來
所需要的元器件
- stm32單片機
- usb-ttl模塊
- stlink
- wifi模塊8066
- 舵機
整體思路
1.stm32先進行wifi模塊初始化,發送AT指令使得wifi模塊進入sta模式,自動發送wifi名稱與密碼連接至手機的熱點,接入TCP,並開啓通透傳遞模式。
2.通過手機發送led信號讓wifi模塊接收到信息,並返回單片機,在串口2上顯示,並翻轉單片機上的led燈,返回連接成功信息到手機上。
3.通過手機發送舵機信號讓wifi模塊接收到信息,返回單片機,在串口2上顯示,並控制連接在單片機上的舵機轉動,返回連接成功信息到手機上。
連線圖
stm32通過uart1與wifi連接,
stlink連接stm32,
usb-ttl連接stm32的uart2,
舵機連接tim4來實現用脈衝控制舵機轉動角度。
完成效果
使程序能夠自行連接給定的WIFI熱點和服務器並實現雙向通信,通過wifi模塊完成手機對stm32外設(燈和舵機)的控制
wifi模塊初始化
wifi模塊的初始化中,有幾個指令是不可缺少的:
- AT測試
- AT+CWMODE=1設置工作模式
- AT+CWJAP=“熱點名稱”,“熱點密碼”
- AT+CIPSTART=“TCP”,“服務器地址”,端口號
代碼解析
- wifi模塊初始化代碼
int wifi_init()
{
uint8_t ret=0;
ret = Send_AT_commend("AT", "OK", 100);
if(!ret)
return -1;
ret = Send_AT_commend("AT+CWMODE=1", "OK", 100);
if(!ret)
return -2;
wifi_str();
ret = Send_AT_commend(temp, "OK", 9000);
if(!ret)
return -3;
server_str();
ret = Send_AT_commend(temp, "OK", 3000);
if(!ret)
return -4;
ret = Send_AT_commend("AT+CIPMODE=1", "OK", 100);
if(!ret)
return -5;
return 1;
}
uint8_t wifi_str()
{
int i=0;
while(temp[i])temp[i++]=0x00;
strcat(temp,"AT+CWJAP=");
strcat(temp,"\"");
strcat(temp,NAME);
strcat(temp,"\",\"");
strcat(temp,PWD);
strcat(temp,"\"");
}
uint8_t server_str()
{
int i=0;
while(temp[i])temp[i++]=0x00;
strcat(temp,"AT+CIPSTART=\"TCP\",\"");
strcat(temp,ADDR);
strcat(temp,"\",");
strcat(temp,PORT);
}
- 發送AT指令部分代碼
uint8_t Send_AT_commend(char *at_commend, char *re_commend, uint16_t time_out)
{
uint8_t i=0;
for(i=0;i<3;i++)
{
clear_buf();
HAL_UART_Transmit(&huart1, (uint8_t *)at_commend, strlen(at_commend), 0xFFFF);
HAL_UART_Transmit(&huart1, (uint8_t *)"\r\n", 2, 0xFFFF); HAL_Delay(time_out);
if(find_str(re_commend))
return 1;
i++;
}
return 0;
}
void clear_buf()
{
uint16_t i;
for(i=0;i<2000;i++)
my_re_buf1[i]=0x00;
HAL_UART_Receive_IT(&huart1,my_re_buf1,1);
}
- 舵機控制代碼
void MG996R_Set_Angle(int16_t angle)
{
if ((-90 <= angle) && (angle <= 90))
{
CCR_value = (10. / 9) * angle + 150;
}
__HAL_TIM_SET_COMPARE(&htim11, TIM_CHANNEL_1, CCR_value);
}
- 串口接收中斷信息
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart==&huart1)
{
HAL_UART_Receive_IT(&huart1,&my_re_buf1[++pt_w1],1);
}
}
- 定時器中斷
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
int i=0,len=0;
if(htim==&htim4)
{
while(pt_r1<pt_w1 )
{
while(pt_r1<pt_w1)
HAL_UART_Transmit(&huart2,&my_re_buf1[pt_r1++],1,1000);
HAL_UART_Transmit(&huart2,(uint8_t *)"\r\n",2,1000);
if(find_str("LED")){
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13); //LED
HAL_UART_Transmit(&huart1, (uint8_t *)"success", 7, 0xFFFF); //return
}
if(find_str("SERVO")){
if(m==0){
MG996R_Set_Angle(-40); //SERVO
m++;
}
HAL_UART_Transmit(&huart1, (uint8_t *)"success", 7, 0xFFFF); //return
}
}
if(pt_r1>=pt_w1)
{
pt_w1=pt_r1=0;
HAL_UART_AbortReceive_IT(&huart1);
HAL_UART_Receive_IT(&huart1,my_re_buf1,1);
}
while(send_buf[i])send_buf[i++]=0x00;
while(pt_r2<pt_w2 )
{
HAL_UART_Transmit(&huart1,&my_re_buf2[pt_r2++],1,1000);
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13); //LED
}
if(pt_r2>=pt_w2)
{
pt_w2=pt_r2=0;
HAL_UART_AbortReceive_IT(&huart2);
HAL_UART_Receive_IT(&huart2,my_re_buf2,1);
}
}
}
遇到的問題
- 剛開始wifi模塊初始化自動加載的時候會出問題,之後發現是初始化代碼裏缺少了通透模式的設定,使得無法通過wifi連續傳遞信息
- 寫代碼的時候容易把函數寫在主程序後,有時候keil會報錯,解決方法是創建一個新的c程序,在主函數裏include這個程序的頭文件,之後引用就不會出現這樣的問題了
- 串口發送與接收十分重要,有時候可以用來檢測wifi模塊是否能連接上stm32
總結
希望自己以後可以碼代碼的時候更加細緻,這樣能讓工程不會因爲一些很小的bug而崩潰。