在这里插入图片描述
参考:STM32F103C8T6最小系统板驱动MPU6050串口打印数据
下图为MPU6050需要用到的引脚(不代表工程中是这么用的)
MPU6050模块A0接地mpu6050地址0x68,A0为高电平mpu6050的地址为0x69。所以这里选择的A0接地mpu6050地址0x68。
系统性实例:管道机器人P_bot的机载通信驿站
工程文件+源码
参考视频:HAL库MPU6050_DMP移植
C8T6:
可以使用使用MicroPython开发ESP32
GPIO可用资源
GPIO 6-11 连接到SPI Flash。
GPIO 34-39 只能作为输入且没有内部上拉,其他的可以作为输入或者输出。
GPIO 20, 24, 28, 29, 30, 31 不对外开放。
GPIO 32,33默认连接到RTC域。可能需要如下设置:
ESP32 LoLin32 精简版
ESP32开发板V1.0.0 Rev1 wifi蓝牙 4MB FLASH
板载led灯由gpio22控制。
相关资料:
1.https://github.com/hallard/lolin32-lite-lora
可以看到默认的IIC引脚,SPI引脚等
参考:使用Blinker控制esp01s Relay继电器模块
#define BLINKER_WIFI //以WIFI方式接入,BLINKER_BLE以蓝牙方式接入
#include
//配置wifi联网模块
char auth[] = "Blinker中申请的密钥";
char ssid[] = "WIFI名字";
char pswd[] = "WIFI密码";
int GPIO = 0;
int pin_state = HIGH; //用于做输出引脚电平的翻转
BlinkerButton Button1("btn-abc");//Blinker app上设置按钮时按钮名要和此一致
// 按下按键就会执行该函数(回调函数)
void button1_callback(const String & state) {
BLINKER_LOG("get button state: ", state); //该句将在串口打印
pin_state = !pin_state;
digitalWrite(GPIO, pin_state);
if(state == "on"){
Blinker.print("switch", "on");//该句将在串口打印
Button1.print("on");//该句将用于APP的按键上显示开关状态
}
if(state == "off"){
Blinker.print("switch", "off");//该句将在串口打印
Button1.print("off");//该句将用于APP的按键上显示开关状态
}
Blinker.delay(500);//操作延时
}
void setup() {
// 初始化串口
Serial.begin(115200);
// 初始化控制继电器的GPIO引脚
pinMode(GPIO, OUTPUT);
digitalWrite(GPIO, LOW);//低电平默认继电器关闭
// 初始化WIFI设置
Blinker.begin(auth, ssid, pswd);
//数据管理,当收到指令的时候会调用该回调函数
Button1.attach(button1_callback);
}
//让程序一直运行
void loop() {
Blinker.run();
}
接线:
OLED —— ESP01s
scl —— TXD GPIO1
sda —— RXD GPIO3
参考:ESP32 CAM GPIO引脚定义
和TTL-USB连接
标注的GND接口好像不行,可以换到左边的GND接口
自我尝试,好像下载的时候需要TTL 3V3连接开发板的5V,运行的时候再切换到开发板的3V3
注意:
下载的时候 ESP32-cam的io0要接GND,下载结束后,必须断开io0和GND的连接。
在arduino IDE 点击烧录上传,然后需要按一下esp32-cam的reset按键,程序才会下载。下载完成后,断开io0的连线,再按一下reset按键,就退出下载模式了,即可正常使用。
在同一网络下,设备通过网页访问ESP32的视频信息
B站教程:
资源链接:https://pan.baidu.com/s/1Y9-rLLmAKPYzBDcrEyuGMw
提取码:2022
我的网盘:链接:https://pan.baidu.com/s/1sawnFJiOFXbIOLIRqy4cxQ
提取码:ul7o
串行并行
串行:一次一位,串行口传输方式为数据排成一行、一位一位送出接收也一样;
并行:一位(比特)时间内可传输一个字符,并行口传输8位数据一次送出.;
同步异步
同步:同步通信要求接收端时钟频率和发送端时钟(外界时钟)频率一致,发送端发送连续的比特流,传输速度比异步传输快;
异步:异步通信时不要求接收端时钟和发送端时钟同步,发送端发送完一个字节后,可经过任意长的时间间隔再发送下一个字节;
UART:(Universal Asynchronous Receiver Transmitter:通用异步收发器/异步串行通信口),是一种通用的串行数据总线,用于异步通信,支持全双工。它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。
IIC总线协议:I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
SPI总线协议:SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议。
RS232接口缺陷:
(1)接口的信号电平值较高( +/-12V),易损坏接口电路的芯片。
(2)传输速率较低,在异步传输时,波特率为20Kbps。
(3)接口使用一根信号线和一根信号返回线而构成共地的传输形式,这种共地传输容易产生共模干扰,所以抗噪声干扰性弱。
(4)传输距离有限,最大传输距离标准值为50英尺,实际上也只能用在50米左右。
RS485是对RS232的改进,特点包括:
①接口电平低,不易损坏芯片。RS485的电气特性:逻辑“1”以两线间的电压差为+(2 ~ 6)V表示,逻辑“0”以两线间的电压差为-(2~6)V表示。接口信号电平比RS232降低了,不易损坏接口电路的芯片。
②传输速率高。10米时,RS485的数据最高传输速率可达35Mbps,在1200m时,传输速度可达100Kbps。
③抗干扰能力强。RS485接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好。
④传输距离远,支持节点多。RS485总线最长可以传输1200m以上(速率≤100Kbps)一般最大支持32个节点,如果使用特制的485芯片,可以达到128个或者256个节点,最大的可以支持到400个节点。
————————————————
原文链接:https://blog.csdn.net/fengge2018/article/details/107592487
参考:小肥侠123
USART与UART的区别?
USART(universal synchronous asynchronous receiver and transmitte): 通用同步异步收发器
USART是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
UART(universal asynchronous receiver and transmitter): 通用异步收发器
异步串行通信口(UART)就是我们在嵌入式中常说的串口,它还是一种通用的数据通信议。
区别:
USART是指单片机的一个端口模块,可以根据需要配置成同步模式(SPI,I2C),也可以将其配置为异步模式,后者就是UART。所以说UART姑且可以称之为一个与SPI,I2C对等的“协议”,而USART则不是一个协议,而是更应该理解为一个实体。(摘自知乎-Sean回答)
相比于同步通讯,UART不需要统一的时钟线,接线更加方便。但是,为了正常的对信号进行解码,使用UART通讯的双方必须事先约定好波特率,即单位事件内传输码元的个数。
————————————————
版权声明:本文为CSDN博主「JYU_hsy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40774605/article/details/88398709
参考:
0.秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4 CAN!
CAN通信详解
1.简述STM32 CAN总线的设置
2.STM32CUBEMX系列——CAN通讯的配置
3.STM32之CAN —CAN ID过滤器分析
4.再谈STM32的CAN过滤器
STM32常用CAN收发器;TJA1050或者82C250。
理想情况下,可以 达 128 个,当然,使用特定的 芯片,可以达到 256 等等,这是由它自身的驱动能力决定的。
在 CAN 总线的起止端有一个 120Ω的终端电阻,是用来来做阻抗匹配,以减少回波反射。
传输数据
每次发送数据前,节点都会监听总线的状态,如果总线状态为空闲时,它就会立即向总线上发送自己的数据,这个数据里不仅有数据,还有本身的ID信息或者其他的控制指令,应称为数据包(数据帧),也叫做报文。当报文被传输到其它节点时,只要这些节点按格式去解读,就能还原出原始数据。
报文: 在原始数据段的前面加上传输起始标签、片选(识别)标签、控制标签,在数据的尾段加上 CRC 校验标签、应答标签和传输结束标签。类似这样的数据包就被称为 CAN 的数据帧。为了更有效地控制通讯,CAN 一共规定了 5 种类型的帧,帧也称为报文。
我们人和人传递信息一般是靠耳朵和嘴巴对吧?Spi通信传递信息是通过接口,来看下图:
spi接口有4根线,分别是CS、SCLK、MOSI、MISO。SCLK是同步信号,一般由主控来控制。既然是通信,自然是需要有个”对象”,如上图A和B。A是SPI Master,也就是主控,比如说单片机,一般就是主控的角色,主控来负责发送SCLK同步信号通知SPI Slave是否需要进行数据通信。B是SPI Slave,也就是从机,比如说Flash芯片。CS代表片选信号,为什么要用片选呢?因为一个SPI Master可以跟不同的SPI Slave进行通信。
SPI Master就是通过CS来控制,具体跟哪个SPI Slave通讯,控制CS为低电平就代表选中该SPI Slave。如果说只跟一个从设备通讯,也可以直接把CS串联电阻接地,省的每次都去控制它。MOSI英文全称是Master Output Slave Input,这个一般接主控器件数据输出引脚,从机器件数据输入引脚。MISO英文全称是Slave Input Master Output,这个一般接主控器件数据输入引脚,从机器件数据输出引脚。除此以外,还有一种特殊的用法,就是只用SCLK和MOSI这两个引脚的SPI通信。比如说我们无际单片机编程实战项目课程里有个OLED屏的应用。
接地了,因为只有一个从设备。我们主要是控制OLED屏去显示内容,并不需要从OLED读取数据,所以MISO也不需要。这种情况是可以只用2根线的。所以,这种协议要从本质上去理解它们,不需要死记硬背要接几个引脚
接法:
经常遇到一些朋友,在设计SPI主机和从机的逻辑互联时,会习惯性地仿照UART上的TXD和RXD交叉连接,而将SPI主机的MISO和从机的MOSI进行逻辑连接,SPI主机的MOSI和从机的MISO进行逻辑连接,结果导致设计错误。这里给大家提供一个不再出错而记忆简单的方法— 理解MISO和MISO缩写的具体含义。
MISO和MOSI的含义以及为何主机从机不能交叉接
信号 MISO = Master In Slave Out,即 在主机这边是输入,在从机那边是输出。
信号 MOSI = Master Out Slave In,即 在主机这边是输出,在从机那边是输入。根据输入接输出,输出接输入的原理,所以,就应该是
SPI主机的 MISO,直接 接 SPI从机的MISO,因为前者是输入,后者是输出。
SPI主机的 MOSI,直接 接 SPI从机的MOSI,因为前者是输出,后者是输入。
也就是,主机的MISO需要接从机的MISO,主机的MOSI需要接从机的MOSI,不能交叉接。
参考:2个STM32串口之间的串口通信(RX,TX)
链接:https://pan.baidu.com/s/1HKGYOi58lC9GUnCSVoRyLQ
提取码:qdzy
历程是根据正点和普中的程序结合改写的。
实现的功能:
串口调试助手1通过单片机1的USART3发送数据,单片机1通过USART1传送发来的数据给单片机2的USART1,单片机2通过串口调试助手2接收数据。(具体内容自己看,多说易混淆)
反之亦然。
具体内容看实验现象。
USB-TTL1的T接单片机1的PB11,USB-TTL1的R接单片机1的PB10;
单片机1的PA9接单片机2的PA10,单片机1的PA10接单片机2的PA9;
USB-TTL2的T接单片机2的PB11,USB-TTL2的R接单片机2的PB10;
在这里插入图片描述左边串口调试助手发送"1"给单片机1的USART3,单片机1的USART3触发接收中断,在中断里面用USART1发送”1“给单片机2的USART1,单片机2的USART1触发接收中断,在中断里面用USART3发送”1“给右边串口调试助手。
反之亦然。
参考:STM32与Arduino串口通信实验
首先说明一下,arduino使用的编码方式是utf8,因此stm32的编码方式也要使用utf8才能发送汉字成功。
然后再说明一下,stm32的串口接收协议里需要接收的数据以0x0d和0x0a结尾,即末尾时\r\n,而arduino的串口协议不需要任何结尾。
stm32的编码方式设置方式为:configuration(小扳手)-> editor -> encoding -> encode in utf-8 without signature
因此为了避免格式错乱,推荐使用英文进行发送!
这里直接演示发送字符串的方式,同理发送字符就是一个字母或数字而已。
一、arduino发送字符串,stm32接收字符串
实验效果为:arduino发送一次数据,灯闪一次;stm32没收到“你好”时,LED2闪烁,收到“你好”时,LED1闪烁,LED2不再闪烁。
1.1 arduino源码
void setup() {
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop() {
digitalWrite(13,LOW);
delay(500);
Serial.print("你好\r\n");
digitalWrite(13,HIGH);
delay(500);
}
注意:stm32是使用了我自建的库函数,是德飞莱尼莫stm32的程序。
1.2 stm32源码
#include "imut_advance.h"
void SysInit()
{
delay_init();
LEDInit(0);LEDInit(1);
}
int main(void)
{
char t;
u16 len;
u8 lalal[]="你好";
u8 mark=0;
delay_init();
LEDInit(2);LEDInit(3);
uart_init(9600);
NVICInit(2,0,USART1_IRQn,2);
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;
for(t=0;t {
if(USART_RX_BUF[t]==lalal[t])mark=1;
else {mark=0;break;}
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
}
if(mark==1)
{
while(1)
{
LED3=!LED3;
delay_ms(500);
}
}
USART_RX_STA=0;
}
LED2=!LED2;
delay_ms(500);
}
}
二、stm32发送字符串,arduino接收字符串
实验效果为:stm32发送完字符串LED2闪烁,arduino接收到字符串时灯闪烁。
arduino源码
char compare[] = "你好";
char comdata[] = "";//字符串函数
int mark;
void setup()
{
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop()
{
if(Serial.available())
{
String comdata = "";//缓存清零
while (Serial.available() > 0)//循环串口是否有数据
{
comdata += char(Serial.read());//叠加数据到comdata
delay(2);//延时等待响应
}
int i=0;
int t;
for (t=0;t {
if(comdata==compare)mark=1;
else{mark=0;break;}
i++;
}
}
if(mark==1)
{
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);
}
}
二、STM32程序
#include "imut_advance.h"
int main()
{
delay_init();
LEDInit(2);LEDInit(3);
KeyInit(0);KeyInit(1);KeyInit(2);
USARTInit(1,9600);
NVICInit(2,0,USART1_IRQn,2);
while(1)
{
LED2=!LED2;
printf("你好");
delay_ms(500);
}
}
三、接线方式
拔掉STM32PA9和PA10的跳冒,
重点来了,STM32和Arduino的电源都不要插在电脑上,否则串口会被占用,嗯,我插在了树莓派上。
此时两个板子的灯都会闪烁。
一些经验(踩过的坑)
1.HAL_UART_Transmit 和 HAL_UART_Transmit_IT区别
2.HAL_UART_Transmit_IT不能连续使用,如果连续使用一般只有后者能成功发送;
3.STM32 和 arduino/ESP32 之间只需要连接 Tx & Rx 线即可(两者交叉连接)。
实验逻辑
1.ESP32 serial2不断发送“R”
2.STM32 开启uart8串口接收中断,若接收到的为“R”,则回复“I got ESP message!”
3.ESP32 受到回复后,将回复打印在电脑串口监视器上。
//UART8´®¿Ú½ÓÊÕÖжϻص÷º¯Êý
uint16_t FOC_buff[5];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == UART8)
{
uint8_t motor1_message[] = "I got MOTOR1 message!\n";
uint8_t end_n = '\n';
HAL_UART_Transmit(&huart8,motor1_message,sizeof(motor1_message)/sizeof(motor1_message[0]), 0xFFFF);
HAL_UART_Transmit(&huart8,rev, 5, 0xFFFF);
HAL_UART_Transmit(&huart8,&end_n, 1, 0xFFFF);
memset(rev, 0, 10);
HAL_UART_Receive_IT(&huart8, rev, 5); //ÖØдò¿ª½ÓÊÕÖжÏ
// if(rev== 'R') //´®¿ÚÖжϽÓÊÕarduinoµÄÐÅÏ¢³É¹¦£¡
// {
uint8_t get_Message[] = "I got ESP message!\n";
uint8_t end_n = '\n';
HAL_UART_Transmit(&huart8,&rev, 1, 0xFFFF);
HAL_UART_Transmit(&huart8,&end_n, 1, 0xFFFF);
HAL_UART_Transmit(&huart8,get_Message,sizeof(get_Message)/sizeof(get_Message[0]), 0xFFFF);
HAL_UART_Receive_IT(&huart8, &rev,1); //ÖØдò¿ª½ÓÊÕÖжÏ
rev = ' ';
// }
// if(rev== 'S')
// {
// //HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
// HAL_UART_Transmit_IT(&huart8,&rev,1);
// HAL_UART_Receive_IT(&huart8, &rev,1);
//
// }
}
}
//Serial2========================Serial2 BEGIN==========================>
while (Serial2.available()) { //外界单片机通过串口发来的电流反馈
// get the new byte:
char inChar = (char)Serial2.read();
// add it to the string buffer:
received_chars += inChar;
// end of user input
if (inChar == '\n') {
// execute the user command
command = received_chars;
//============================2022/11/17 Xwave ADD BEGIN====================
/*
if (inChar != '\n') received_chars += inChar;
else if (inChar == '\n') //当遇到换行符号,将接收到的数据打印
{
Serial.println("来自串口的信息:");
Serial.println(received_chars);
}
String motor1_str = received_chars;
int motor1_int = motor1_str.toInt(); //Arduino string 转为int
double motor1_current = motor1_str.toDouble(); //Arduino string 转为double
*/
//============================2022/11/17 Xwave ADD END====================
/* execute the user command */
//根据逗号分离两组字符串
//想象中双足轮通讯数据格式:高度,指令 指令格式:英文+值
commaPosition = command.indexOf(',');//检测字符串中的逗号
if(commaPosition != -1)//如果有逗号存在就向下执行
{
motor1_Serial2_angle = command.substring(0,commaPosition).toDouble(); //一号电机对应的反馈电流
motor2_Serial2_angle = command.substring(commaPosition+1, command.length()).toDouble();
// Serial.print("motor1_current:");
// Serial.println(motor1_current);
// Serial.print("motor2_current:");
// Serial.println(motor2_current);
Serial.print("motor1_Serial2_angle:");
Serial.println(motor1_Serial2_angle);
Serial.print("motor2_Serial2_angle:");
Serial.println(motor2_Serial2_angle);
}
// reset the command buffer
received_chars = "";
}
}
//============================2022/11/17 Xwave ADD BEGIN====================
//串口2 向STM32发送
//char a = 'R';
//Serial2.print('R');
if( (sensor.getAngle() > 0.2 || sensor.getAngle() < -0.2) || (sensor1.getAngle() > 0.2 || sensor1.getAngle() < -0.2) )
{
sum++;
if(sum>100)
{
sum = 0;
char MOTOR_angle[20];
sprintf(MOTOR_angle, "%f,%f", sensor.getAngle(), sensor1.getAngle());
Serial2.println(MOTOR_angle);
//Serial.println(MOTOR_angle);
memset(MOTOR_angle, 0, sizeof(MOTOR_angle));
}
}
//============================2022/11/17 Xwave ADD END====================
//Serial2========================Serial2 END==========================>
void CANFilter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0; //CAN过滤器编号,范围0-27
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //CAN过滤器模式,掩码模式或列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //CAN过滤器尺度,16位或32位
sFilterConfig.FilterIdHigh = 0; //32位下,存储要过滤ID的高16位
sFilterConfig.FilterIdLow = 0; //32位下,存储要过滤ID的低16位
sFilterConfig.FilterMaskIdHigh = 0; //掩码模式下,存储的是掩码
sFilterConfig.FilterMaskIdLow = 0;
sFilterConfig.FilterFIFOAssignment = 0; //报文通过过滤器的匹配后,存储到哪个FIFO
sFilterConfig.FilterActivation = ENABLE; //激活过滤器
sFilterConfig.SlaveStartFilterBank = 0;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
在这里插入代码片void CAN_User_Init(CAN_HandleTypeDef* hcan ) //Óû§³õʼ»¯º¯Êý
{
CAN_FilterTypeDef sFilterConfig;
HAL_StatusTypeDef HAL_Status;
sFilterConfig.FilterActivation = ENABLE; //¼¤»î¹ýÂËÆ÷
sFilterConfig.FilterBank = 1; //¹ýÂËÆ÷1
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //ÉèΪÑÚÂëģʽ
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //ÉèΪ32λ
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //½ÓÊÕµ½µÄ±¨ÎÄ·ÅÈëµ½FIFO0ÖÐ
sFilterConfig.FilterIdHigh = 0x1ff<<5; //把基本ID放入到STID中
sFilterConfig.FilterIdLow = 0x1ff0<<5;
sFilterConfig.FilterMaskIdHigh =0xffff;
sFilterConfig.FilterMaskIdLow =0xffff;
sFilterConfig.SlaveStartFilterBank = 0;
HAL_Status=HAL_CAN_ConfigFilter(hcan, &sFilterConfig);
HAL_Status=HAL_CAN_Start(hcan); //¿ªÆôCAN
if(HAL_Status!=HAL_OK){
// printf("¿ªÆôCANʧ°Ü\r\n");
}
HAL_Status=HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
if(HAL_Status!=HAL_OK){
//printf("¿ªÆô¹ÒÆðÖжÎÔÊÐíʧ°Ü\r\n");
}
}
这样设置也可
sFilterConfig.FilterIdHigh = 0x1ff<<5; //把基本ID放入到STID中
sFilterConfig.FilterIdLow = 0;
sFilterConfig.FilterMaskIdHigh =0xffff;
sFilterConfig.FilterMaskIdLow =0;
原先是robomaste A板和GM6020电机之间进行CAN通信,
电机可以通过拨码设置ID,1到7
电机CAN波特率:1Mbps
而A板的波特率设置却为:X M/3/(9+4+1)=X bps
技术指标
CAN_TxHeaderTypeDef Can_Tx;
CAN_RxHeaderTypeDef Can_Rx;
uint8_t Rxdata[8];
uint8_t Txdata[8] = {0};
extern uint8_t can_rx_finish_flag;
//stm32f1xx_it.c中 CAN接收中断函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan1)
{
uint8_t i;
printf("***********************************************\r\n");
HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&Can_Rx,Rxdata);
can_rx_finish_flag=1;
printf("RX ID:0x%X\r\n",Can_Rx.StdId);
printf("RX DATA: %02X%02X%02X%02X%02X%02X%02X%02X\r\n",Rxdata[0],Rxdata[1],Rxdata[2],Rxdata[3],Rxdata[4],Rxdata[5],Rxdata[6],Rxdata[7]);
CH3 = (Rxdata[4]<<8) | Rxdata[5];
CH4 = (Rxdata[6]<<8) | Rxdata[7];
printf("CH3:%d CH4:%d\r\n", CH3, CH4);
}
/* USER CODE END 1 */
#define PIN 12
void setup(){
digitalWrite(PIN,HIGH);
pinMode(PIN,OUTPUT);
}
void loop(){
digitalWrite(PIN,LOW);
}
Serial.begin(9600);` //打开串口
Serial.println("Key Down");
Serial.println(a.DEC) //以十进制输出a的值;
Serial.print("Hello warld!\n");
// Serial.println() 不能像printf那样格式化输出很多变量,可以用以下方式
char R_nums[20];
sprintf(R_nums, "R1:%d | R2:%d", val1, val2);
Serial.println(R_nums);
memset(R_nums, 0, sizeof(R_nums));
//或者用笨方法,多行Serial.println()
Serial.print(val1);
Serial.print(" | ");
Serial.println(val2);
2.串口输入:
使用Serial.available()来检测串口缓冲区中是否有可读数据,然后再使用Serial.read()读取数据;
if(Serial.available());
{
while(n--)
{
c = Serial.read();
Serial.print(c);
}
}
pin:为引脚的编号
mode:该引脚的模式,
INPUT:输入模式,
OUTPUT:输出模式, 在此模式下digitalWrite和digitalRead都可以使用。
INPUT_PULLUP:输入上拉模式
#define LED PB5 //定义LED引脚为13
#define BUTTON PE3 //定义按钮开关引脚为12
int val = 0; //变量val用来储存按钮状态
int old_val = 0; //暂存val变量的上一个时间单位
int state = 0; //0表示LED关闭,1表示打开
void setup(){
pinMode(LED, OUTPUT); //设定LED引脚为输出状态
pinMode (BUTTON,INPUT); //设定按钮引脚为输入状态
}
void loop(){
val = digitalRead(BUTTON); //读取按钮状态并储存
//检查按钮的变化情况
if(val == HIGH){
digitalWrite(LED,HIGH);
}
else{
digitalWrite(LED,LOW);
}
}
pin:对于 ATmega168芯片的Arduino(包括Mini或BT),
该函数可以工作于 3, 5, 6, 9, 10和 11号接口
value表示为0~255,对应0 到 100%占空比,同时也对应0~5V电压。
int analogRead(pin)
val = analogRead(2); //读出类比脚位 2 的值并赋值给 val
#如果要这个引脚输出的话,记得要在setup()函数里面声明
pinMode(4,OUTPUT); int analogRead(pin)前面也可以设置引脚模式。
通过使用**analogRead()**函数,我们可以读取施加到其中
一个引脚的电压。比如可以读模拟传感器(10位AD,0~5V表示为0~1023)。
analogWrite(pin,val)往指定pin引脚写入数据
例如analogWrite(4,520),表示给D4这个角写入占空比为520/1024的pwm波。
这里要说明一下,analogWrite()默认的频率是1khz,默认占空数值是1024。
如果要这个引脚输出的话,记得要在setup()函数里面声明
pinMode(4,OUTPUT);
analogWriteRange(new_range)
可以改变占空数值,默认是1024,可以改成2048,这样精度就提高了1倍,其实也只是控制输出而已,实际我感觉没卵用。
analogWriteFreq(new_frequency)
设置新的pwm频率,analogWrite()默认是1khz,可以设置成别的,其实改变的是周期。
ESP32在arduino中没有提供PWM例程,没有像Arduino 官方板子之类的有analogWrite方法
参考:CSDN
(1)RESET中断,就是当RESET管脚接低电平,则中止当前程序,重启CPU
(2)时钟中断,是指设定CPU内部定时器后,当到达指定时间,将产生中断请求。常用于定时。
(3)外部中断,就是当CPU的外部中断管脚电平变动时,将产生中断请求。
常用于键盘输入、串口通信等。
外部中断
attachInterrupt( digitalPinToInterrupt(pin) , function, mode)
(1)digitalPinToInterrupt(pin) :取得引脚pin的中断号
(2)function:中断发生时调用的函数,此函数必须不带参数和不返回任何值。该函数称为中断服务程序。
(3)mode:定义何时发生中断以下四个contstants预定有效值:
LOW 当引脚为低电平时,触发中断
CHANGE 当引脚电平发生改变时,触发中断
RISING 当引脚由低电平变为高电平时,触发中断
FALLING 当引脚由高电平变为低电平时,触发中断.
arduino通过串口接收到的字符串数据需要转化为其他类型,才能用于其功能实现。
//字定义需要转换的字符串数据
String my_str = "12345.123";
//字符串转换成整型数据;
int my_int = my_str.toInt();
Serial.println(my_int);
//字符串转换成Float类型
Serial.println(my_str.toFloat());
//字符串转换成Double类型
Serial.println(my_str.toDouble();
//整型转换成字符串,
int ty = 1000;
String mystr=String(ty);
Serial.println(mystr+mystr);
参考:CSDN1ESP-Arduino(四) PWM波形控制输出
可用于驱动舵机,改一下也可用于LED调光
连接方式:
红线—5v
黑线—GND
黄线—PIN16
#include
//通过ESP32的 LEDC 来实现PWM
int freq = 50; // 频率(20ms周期)
int channel = 8; // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
int resolution = 8; // 分辨率
const int led = 16;
int calculatePWM(int degree)
{ //0-180度
//20ms周期,高电平0.5-2.5ms,对应0-180度角度
const float deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256))
const float max = 32;//对应2.5ms
if (degree < 0)
degree = 0;
if (degree > 180)
degree = 180;
return (int)(((max - deadZone) / 180) * degree + deadZone);
}
void setup()
{
Serial.begin(9600);
ledcSetup(channel, freq, resolution); // 设置通道
ledcAttachPin(led, channel); // 将通道与对应的引脚连接
}
void loop()
{
for (int d = 0; d <= 180; d += 10)
{
ledcWrite(channel, calculatePWM(d)); // 输出PWM
Serial.printf("value=%d,calcu=%d\n", d, calculatePWM(d));
delay(1000);
}
}
LED控制(LEDC)外围设备主要用于控制LED的强度,尽管它也可以用于生成PWM信号用于其他目的。它具有16个通道,可以生成独立的波形,这些波形可以用于驱动RGB LED器件。
参考:yushuir
舵机的控制就是通过一个固定的频率,给其不同的占空比的,来控制舵机不同的转角
舵机的频率一般为频率为50HZ(周期:20ms),也就是一个20ms左右的时基脉冲,而脉冲的高电平部分一般为0.5ms-2.5ms范围(也就是占空比2.5%-12.5%)。来控制舵机不同的转角
500-2500us的PWM高电平部分对应控制180度舵机的0-180度
以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
//加入头文件
#include "oled.h"
int main(void)
{
unsigned char BMP[300];
OLED_Init();
OLED_Clear();
OLED_ShowString(0, 0, "P_bot: by XWAVE", 16);
OLED_Clear();
OLED_ShowString(0, 0, "P_bot:>", 16);
HAL_Delay(500);
//...
OLED_ShowString(0, 0, "P_bot:>>>>ready", 16);
HAL_Delay(500);
OLED_Clear();
while (1)
{
char IMU_str1[100];
char IMU_str2[100];
memset(IMU_str1, 0, sizeof(IMU_str1));
memset(IMU_str2, 0, sizeof(IMU_str2));
sprintf(IMU_str1, "X:%6.1f¡ãY:%4.1f¡ã\r\n", roll, pitch);
sprintf(IMU_str2, "Z:%6.1f¡ãT:%2.f¡ãC\r\n", yaw, temp/100);
//屏幕上打印变量
OLED_ShowString(0, 2, IMU_str1, 10);
OLED_ShowString(0, 3, IMU_str2, 10);
}
}