目录
一、STM32
1.1引脚
1.1.1 HALIO输入输出
void io_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0); /* KEY0时钟使能 */
gpio_init_struct.Pin = GPIO_PIN_12; /* KEY0引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */
gpio_init_struct.Pin = GPIO_PIN_13; /* KEY1引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* KEY1引脚模式设置,上拉输入 */
gpio_init_struct.Pin = GPIO_PIN_15; /* WKUP引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* WKUP引脚模式设置,下拉输入 */
gpio_init_struct.Pin = GPIO_PIN_14; /* WKUP引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP ; /* 输出 */
gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* WKUP引脚模式设置,下拉输入 */
}
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15) == 0&&KEY3LAST==1){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14,1);
}KEY3LAST = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15);
1.1.2 标准库库IO输入输出
#define LEDC PCout(13)
void IO_init(){//初始化PA0-15为输出后在main.c中通过移位对PA引脚进行控制
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //PB5引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //上拉输入模式
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PB5引脚
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA| RCC_APB2Periph_AFIO, ENABLE); //使能GPIOB时钟//AFIO必须开启
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//要先开时钟,再重映射;这句表示关闭jtag,使能swd。B23
1.1.3 步进电机
unsigned char motorA[] = {0,0,0,0,0,1,1,1};
unsigned char motorB[] = {0,0,0,1,1,1,0,0};
unsigned char motorC[] = {0,1,1,1,0,0,0,0};
unsigned char motorD[] = {1,1,0,0,0,0,0,1};//步进电机移位控制
void IO_init(){//初始化PA0-15为输出后在main.c中通过移位对PA引脚进行控制
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; //PB5引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //上拉输入模式
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB5引脚
}
//count=5 times=68(count是转速5正常,times是时长68为一秒)
void mcrun(int count,int times){
unsigned char i=0;
if(count>15)count=15;
if(count<5)count=5;
while(times--){
for(i=0;i<8;i++){
DC1 = ~motorA[i];
DC2 = ~motorB[i];
DC3 = ~motorC[i];
DC4 = ~motorD[i];
delay_ms(count);
}
}
DC1 = 0x00;
DC2 = 0x00;
DC3 = 0x00;
DC4 = 0x00;
}
1.1.4 KEY消抖
if(KEY1==0){
delay_ms(10);
if(KEY1==0){
while(KEY1==0);
}
}
1.2 OLED显示
1.2.1 Sptintf
- 头文件
#include "stdio.h"
- 变量定义
char tempmaxs[20];
Int tempmax;
- 函数
sprintf(tempmaxs,":%d",tempmax);
1.3延迟
1.3.1 SysTick_Config系统中断的微秒延迟
void delay_us(uint32_t nus)
{
uint32_t tickStart, tickCur, tickCnt;
uint32_t tickMax = SysTick->LOAD;
uint32_t udelay_value = (SysTick->LOAD/1000)*nus;
tickStart = SysTick->VAL;
while(1)
{
tickCur = SysTick->VAL;
tickCnt = (tickStart < tickCur) ? (tickMax+tickStart-tickCur) : (tickStart-tickCur);
if (tickCnt > udelay_value)
break;
}
}
1.4 ESP01S作为服务器发送(弃用)
//定义存储数据的数组
char temp[100];
//字符串长度计算
char temp2[100];
int str_len(char *str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
sprintf(temp,"123:\r\n");//存储指定数据
length= str_len(temp);//计算长度
DEBUG_USARTx = USART1;//使用PA9串口
sprintf(temp2,"AT+CIPSEND=0,%d\r\n",length);//AT发送的格式转换
printf(temp2);//转换后发送AT指令
delay_ms(1000);//等待WIFI应答
delay_ms(1000);
printf(temp);//发送数据
1.4.1 STM32配置ESP01S为客户端模式
1.5串口处理
1.5.1 1a2a3a间隔数据处理
函数长度固定:
//函数输入字符串数组的名称
//自动使用printf发送隔开的数据
void extractNumbers(char* str) {
int len = strlen(str);
int i;
char number[20]; // 假设最长的数字不超过20位
int numberIndex = 0;
for (i = 0; i < len; i++) {
if (str[i] == 'a') {
number[numberIndex] = '\0'; // 添加字符串结束符
printf("%s\n", number); // 打印提取出来的数字
numberIndex = 0; // 重置索引,准备提取下一个数字
} else {
number[numberIndex] = str[i];
numberIndex++;
}
}
// 处理最后一个数字
number[numberIndex] = '\0';
printf("%s\n", number);
}
函数长度可以控制:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* convert_to_int_array(char* str, int num_numbers) {
int* result = (int*)malloc(num_numbers * sizeof(int));
char* token;
char* delim = "a";
int i = 0;
token = strtok(str, delim);
while (token != NULL && i < num_numbers) {
result[i++] = atoi(token);
token = strtok(NULL, delim);
}
return result;
}
int main() {
char input_str[] = "123a456a789a1003a1a";
int num_numbers = 4;
int* result = convert_to_int_array(input_str, num_numbers);
for (int i = 0; i < num_numbers; i++) {
printf("%d ", result[i]);
}
printf("\n");
free(result);
return 0;
}
1.5.2 接收发送回显
- 接收与回显
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n\r\n");
for(t=0;t<len;t++)
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
Data_Processing(len);//转存函数
USART_RX_STA=0;
}
- 转存
uint8_t DataRxbuf[512] = {0};
void Data_Processing(int longth){
unsigned int i=0;
memset(DataRxbuf, 0, sizeof(DataRxbuf));
for(i=0;i<longth;i++){
DataRxbuf[i] = USART_RX_BUF[i];
}
DataRxbuf[longth] = '\0';
}
- 发送
printf("\r\n\r\n");//插入换行
printf(&DataRxbuf[0]);//发送函数
printf("\r\n\r\n");//插入换行
printf(DataRxbuf);//发送函数
printf("\r\n\r\n");//插入换行
- 全部
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n\r\n");
for(t=0;t<len;t++)
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
Data_Processing(len);
printf("\r\n\r\n");//插入换行
printf(&DataRxbuf[0]);
printf("\r\n\r\n");//插入换行
printf(DataRxbuf);
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}
1.6 STM32简易版发送APP数据
变量与引用:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
u8 lcd_id[50];
首先使用STM32源码里的文件配置串口,接下使用WIFIINIT配置模块。来使用PRINITF发送数据
void wifinit(){
DEBUG_USARTx = USART2;
printf("AT+CWMODE=2\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s、
printf("AT+CWMODE=2\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s
printf("AT+CIPMUX=1\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s
printf("AT+CIPMUX=1\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s
printf("AT+CIPSERVER=1,5000\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s
printf("AT+CIPSERVER=1,5000\r\n");
delay_ms(1000); //延时1s
delay_ms(500); //延时1s
DEBUG_USARTx = USART1;
}
sprintf((char*)lcd_id,"l1:%d l3:%d Temp:%d Humi:%d\r\n",(int)temper,(int)mq2,(int)length,(int)Weight_Shiwu);
lenstring = strlen((char*)lcd_id);
DEBUG_USARTx = USART2;
sprintf((char*)lcd_id,"AT+CIPSEND=0,%d\r\n",lenstring-1);
printf((char*)lcd_id);
delay_ms(500);
printf("l1:%d l3:%d Temp:%d Humi:%d\r\n",(int)temper,(int)mq2,(int)length,(int)Weight_Shiwu);
DEBUG_USARTx = USART1;
1.7 SG90舵机常用程序
1.7.1 舵机正反转次数限制
u8 sg_flag = 1,angle;
void SG90(i){
if(i==1&&sg_flag==0){
sg_flag=1;
for(angle=5;angle<=50;angle+=5)//从5到175度,步进5度
{
servo_angle(angle);
delay_ms(200);
}
}
else if(i==0&&sg_flag==1){
sg_flag=0;
for(angle=50;angle>=5;angle-=5)//从175到5度,步进5度
{
servo_angle(angle);
delay_ms(200);
}
}
}
2.1 线程
2.1.1 类线程重复执行刷新UI
//在114查看后更新mainjava和增加DataTransmission类(类见附录1)
(1)按键触发线程开启
buttonref.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
runOnUiThread(new Runnable() {//更新UI
@Override
public void run() {
RuntestThread runtestThread = new RuntestThread();
runtestThread.start();
}
});
}
});
- 线程内容
class RuntestThread extends Thread{
public void run(){
while (true) {
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable()
{
public void run() {
// TODO Auto-generated method stub
String recv_dataName = DataTransmission.getInstance().getData();
if (recv_dataName!=null)
{
int num = Integer.parseInt(recv_dataName);
if(num == 122){
//dengtyp.setText("灯:OPEN");
}
if(num == 123){
//dengtyp.setText("灯:CLOSE");
}
if(num == 124){
//mentpe.setText("门:CLOSE");
System.out.println("开门");
}
if(num == 125){
//mentpe.setText("门:OPEN");
System.out.println("关门");
}
if(num == 126){
// chuantyp.setText("窗:OPEN");
System.out.println("开窗");
}
if(num == 127){
//chuantyp.setText("窗:CLOSE");
System.out.println("关窗");
}
}
}
});
}
}
}
2.1.2 UI线程处理STM32数据
数据类型:“a12a13a0a12a15”数据量为5整形
String[] parts = recv_dataName.split("a");
// 2. 将每个子字符串解析为整数并存储到整型变量中
int[] numbers = new int[parts.length];
for (int i = 0; i < 6; i++) {//数据对应I为6
if (!parts[i].isEmpty()) { // 检查字符串是否为空
numbers[i] = Integer.parseInt(parts[i]); // 解析为整数
System.out.println("Number " + i + ": " + numbers[i]);
}
}
temp = findViewById(R.id.txttemp);
humi = findViewById(R.id.txthumi);
light = findViewById(R.id.txtlight);
fire = findViewById(R.id.txtfire);
hcsr = findViewById(R.id.txthcsr);
temp.setText(numbers[1]+"℃");//数据最小从1开始计算
humi.setText(numbers[2]+"%");
light.setText(numbers[3]+"LUX");
if(numbers[3] == 1){
fire.setText("检测到火焰");
}
hcsr.setText(numbers[5]+"cm");
2.2 开启网页窗口登录IP
第一步:把下列代码放在public class TicketsActivity extends AppCompatActivity类中
private void initWebView() {
webView = (WebView) findViewById(R.id.mywebview);
WebSettings webSettings = webView.getSettings();
webView.setVerticalScrollBarEnabled(false);
//设置缓存
webSettings.setSaveFormData(false);
webSettings.setSavePassword(false);
//设置JS支持
//webSettings.setJavaScriptEnabled(true);
//设置支持缩放变焦
webSettings.setBuiltInZoomControls(false);
//设置是否支持缩放
webSettings.setSupportZoom(false);
//设置是否允许JS打开新窗口
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// 修复一些机型webview无法点击
webView.requestFocus(View.FOCUS_DOWN);
webView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
if (!v.hasFocus()) {
v.requestFocus();
}
break;
}
return false;
}
});
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("http:") || url.startsWith("https:") ) {
view.loadUrl(url);
return false;
}else{
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
});
}
第二步:在按键中添加以下代码
private WebView webView ;//放在主类中
//WebView在widgets中
initWebView();
WebSettings settings = webView.getSettings();
settings.setUserAgentString("pc/XXX");//添加UA, “app/XXX”:是与h5商量好的标识,h5确认UA为app/XXX就认为该请求的终端为App
settings.setJavaScriptEnabled(true);
//设置参数
settings.setBuiltInZoomControls(true);
settings.setAppCacheEnabled(true);// 设置缓存
webView.setWebChromeClient(new WebChromeClient());
webView.loadUrl("http://192.168.30.235/");
//如果出现net:ERR_CLEARTEXT_NOT_PERMITTED
在对AndroidManifest.xml文件做修改: 在 <application中添加
android:usesCleartextTraffic="true"
2.3 APP Client发送
按键触发:
TCPService.sendStr(String.valueOf("led on"));
Toast.makeText(getApplicationContext(), "已发送", Toast.LENGTH_SHORT).show();
还需要在oncreat中加入:
cmdReceiver =new cmdReceiver();
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.example.communication.data");
getApplication().registerReceiver(cmdReceiver,intentFilter);
声明:
public cmdReceiver cmdReceiver;
加入类:
public class cmdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
recieveData =intent.getStringExtra("data"); //用于保存接收的数据
//DataHandle(recieveData);
}
}
2.4 GPT布局
请使用linerlayout把上面的元素两两组合起来
2.5 解析空格分隔符数据
public class NumberExtractor {
public static void main(String[] args) {
String input = "28 433 26 3704 2020 0";
int[] extractedNumbers = extractNumbers(input, 6); // 可以根据需要修改第二个参数来控制截取数字的个数
for (int num : extractedNumbers) {
System.out.println(num);
}
}
public static int[] extractNumbers(String input, int count) {
String[] numbers = input.split(" ");
int[] extractedNumbers = new int[count];
for (int i = 0; i < count; i++) {
extractedNumbers[i] = Integer.parseInt(numbers[i]);
}
return extractedNumbers;
}
}
//效果如下所示:
2.6 TCP SERVER发送函数
public void sendDataToServer(final String data) {
new Thread(new Runnable() {
@Override
public void run() {
try {
OutputStream os = MainActivity.tcp_client_socket.getOutputStream();
if (!TextUtils.isEmpty(data)) {
os.write(data.getBytes());
Looper.prepare();
Toast.makeText(getApplicationContext(), "已发送", Toast.LENGTH_SHORT).show();
Looper.loop();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
附录1
package com.example.tcpassistant;
public class DataTransmission {
private static DataTransmission instance;
private String data;
private DataTransmission() {}
public static DataTransmission getInstance() {
if (instance == null) {
instance = new DataTransmission();
}
return instance;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}