stm32-定时器输出比较PWM

目录

一、输出比较简介

二、PWM简介

三、输出比较模式实现

1.输出比较框图(以通用定时器为例)

2.PWM基本结构

四、固件库实现

1.程序1:PWM呼吸灯

 2.程序2:PWM驱动直流电机

3.程序3:控制舵机 


一、输出比较简介

6427569e13dc4058bc4108d2252324d8.png

死区生成和互补输出一般用于对电机的控制  

二、PWM简介

217520c3ee6d4309a335940969b560c2.png

 惯性系统:即要能使人眼产生视觉停留的系统

三、输出比较模式实现

4df2aa6225314807bd9e305e6156d983.png

1.输出比较框图(以通用定时器为例)

b20f276000924d83b123d9bcd4402f15.pngd5b1cc384dcb4bff8e3172aa26bb5cdb.pngebc01af3e04148d988d242ccd5663b17.png 

 高级定时器比通用定时器多了个互补输出和死区生成852fe456c92146febbc5a922cc620899.png

如右图,两个mos管构成了推挽电路,上管导通下管关闭输出高电平,下管导通上管关闭输出低电平,两管都关闭为高阻态,两管都导通为短路,会对元器件造成损伤,所以两管不能同时导通

互补输出:当单片机要控制这个电路时,就需要两个输出端口,且二者电平要相反,即互补,而这里OC1和OC1N就是互补的两个端口,即互补输出

死区发生器:但是若在上管关闭的瞬间下管就导通,很可能由于器件的不理想而出现上下管都导通的情况,为了避免这种情况发生,于是又是死区发生器,即他可以在上管关闭后延迟一段时间再导通下管,避免同时导通

2.PWM基本结构

10788d1f0c4c4fc9bf92ee1f9302d992.png

1e024aa74b8a49988ef208aef673b9f7.png

四、固件库实现

1.程序1:PWM呼吸灯

1.我使用的是TIM3的CH2的重定义引脚PB5,所以要打开AFIO时钟

2.开启TIM3和GPIO的时钟

3.初始化GPIO结构体。注意:要记得使用库函数进行重定义

4.选择TIM3的时钟输入,可以为内部时钟,外部时钟模式1和2,

        外部时钟模式1:来源可以是ITR(其他定时器,多用于定时器级联),可以是ETR(外部时  钟),可以是CH1引脚的边沿,CH1引脚和CH2引脚(多用于输入捕获测频率)

        外部时钟模式2:ETR的触发控制模式

5.初始化TIM3结构体--配置PSC,ARR,计数模式,等等

6.初始化OC结构体--PWM模式选择,CCR,输出ref的有效电平

7.定时器使能

//使用TIM3的通道2的重定义引脚PB5-指南者上面是红灯
//我们配置
void PWM_Config()
{
	//首先开启GPIO时钟
	//开启AFIO时钟,因为用到了重定义
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
	//开启定时器的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	//重定义引脚
	//选择部分重定义
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
	
	//初始化GPIO结构体-PB5-输出比较
	GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;//复用推挽,手册可看
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
  GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//选择TIM3的时钟输入
	TIM_InternalClockConfig(TIM3);//我们直接使用内部时钟
	
	//配置TIM结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;//PSC
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数模式
	TIM_TimeBaseInitStruct.TIM_Period = 100-1;//ARR
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//输入滤波器的分频
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
	
	//初始化OC结构体
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//先赋初值,因为我们没有把结构体配置完全
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//模式选择-PWM1
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//输出使能
	TIM_OCInitStruct.TIM_Pulse = 0;//CCR,这里我们不配置CCR的值,后面用一个库函数直接在主函数            
                                     里面配置,实现呼吸灯
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出ref极性,选择有效电平,即ref有效时输出高电平
	//TIM_OCInitStruct.TIM_OCNPolarity = ;
	//TIM_OCInitStruct.TIM_OCIdleState = ;
	//TIM_OCInitStruct.TIM_OCNIdleState = ;
	//TIM_OCInitStruct.TIM_OutputNState = ;
	TIM_OC2Init(TIM3,&TIM_OCInitStruct);
	
	//启动定时器
	TIM_Cmd(TIM3,ENABLE);
	
}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM3,Compare);
}
main.c

#include "stm32f10x.h"   // Device header
#include "bsp_led.h"
#include ".\tim\bsp_tim.h"

extern uint16_t Num;//定时器都是16位的

int i;
void Delay(u32 i)
{
    u32 temp;
    SysTick->LOAD=9000*i;      //设置重装数值, 72MHZ时
    SysTick->CTRL=0X01;        //使能,减到零是无动作,采用外部时钟源
    SysTick->VAL=0;            //清零计数器
    do
    {
        temp=SysTick->CTRL;       //读取当前倒计数值
    }
    while((temp&0x01)&&(!(temp&(1<<16))));    //等待时间到达
    SysTick->CTRL=0;    //关闭计数器
    SysTick->VAL=0;        //清空计数器
}


//ARR=99-->PWM一个周期是100,那么分辨率为1%
//占空比 = CCR/(ARR+1) 
//频率 = 计数器溢出频率 = CK_PSC/(PSC+1)/(ARR+1) = 72M/720/100= 1000HZ ->1ms
int main()
{

	LED_GPIO_Config();
	PWM_Config();
	
	while(1)
	{
		for(i=0;i<=100;i++)
		{
			PWM_SetCompare2(i);
			Delay(10);
		}
		for(i=100;i>=0;i--)
		{
			PWM_SetCompare2(i);
			Delay(10);
		}
	}
}


 2.程序2:PWM驱动直流电机

具体TIM的配置过程同呼吸灯一样,同样是输出不同的PWM占空比来实现电机的不同速度

我们需要三个引脚,一个输出PWM给电机,两个接电机的控制引脚

  • 使用PA2输出PWM,AIN1/2接到PA4/5
  • 频率设置为1KHZ(可以自己随便设置)
  • 定义一个八位有符号的变量Speed,+:正转  -:反转
  • 使用GPIO_SetBits/ResetBits();来设置AIN1/2的电平高低
  • 使用按键来改变转速
void PWM_Config()
{
	//开启时钟
	//使用TIM2的CH3的PA2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启PWM引脚


	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;//复用推挽,手册可看
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 ;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
	TIM_InternalClockConfig(TIM2);
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	//配置1KHZ的PWM
	TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1;//PSC-预分频器
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 
	TIM_TimeBaseInitStruct.TIM_Period = 100-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
																													也可以由内部时钟加一个时钟分频而来,
																													分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//初始化OC-输出比较结构体
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//因为结构体里面的成员有些是高级定时器采用得到,所以这里就先全部初始化一遍,然后再配置具体的值
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	//TIM_OCInitStruct.TIM_Pulse = 50;//CRR 
	TIM_OCInitStruct.TIM_Pulse = 0;//输出要求波型,这里的CRR就不需要了,用固件库的一个函数 TIM_SetCompare3 直接配置CRR
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性
	TIM_OC3Init(TIM2,&TIM_OCInitStruct);//CH3通道
	
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);

}
//电机控制函数

void Motor_SetSpeed(int8_t Speed)//+:正转 -:反转
{
	if(Speed >= 0)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_4);
		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
		TIM_SetCompare3(TIM3,Speed);
	}
	else 
	{
		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
		GPIO_SetBits(GPIOA,GPIO_Pin_5);
		TIM_SetCompare3(TIM3,-Speed);
	}
}
//主函数


#include "stm32f10x.h"   // Device header
#include ".\tim\bsp_tim.h"
#include ".\KEY\bsp_key.h"

uint8_t KeyNum;
int8_t Speed;

int main()
{
	KEY_GPIO_Config();
	PWM_Config();
	
	while(1)
	{
		KeyNum = Key_Scan();
		if(KeyNum == 0)
		{
			Speed += 20;
			if(Speed > 100)
			{
				Speed = -100;
			}
		}
		else if(KeyNum == 1)
		{
			Speed -= 20;
			if(Speed < -100)
			{
				Speed = 100;
			}
		}
		Motor_SetSpeed(Speed);
    }
}

3.程序3:控制舵机 

0ee84118f09c434898681decee12dc1c.png

-TB6612驱动板

VM->STLINK的5v

VCC->面包板3.3v

GND->面包板负极

AO1 AO2 接电机

STBY->待机控制引脚,这里不需要待机,接面包3.3v

AIN1/2-> 任意接两个引脚

PWMA->PWM输出控制引脚

驱动VM放在左下角使用PA2输出PWM,AIN1/2接到PA4/5

  • 要点:输出如上图右侧所示的PWM波型
  • 指南者的PA0引脚为按键1,所以使用TIM2的CH3通道的PA2
  • PWM要求频率为50HZ,即总时间20ms,高电平占0.5~2.5ms,这里我们可以给ARR配置20000-1,PSC配置72-1
  • 封装Angle转换函数0-50  180->2500   -->y=Angle/180*2500+50, Angle使用浮点型,利于计算
  • 使用按键来改变角度

#include "bsp_tim.h"

void PWM_Config()
{
	//开启时钟
	//使用TIM2的CH3的PA2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启PWM引脚


	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;//复用推挽,手册可看
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
	TIM_InternalClockConfig(TIM2);
	//初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;//PSC-预分频器
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数 
	TIM_TimeBaseInitStruct.TIM_Period = 20000-1;//ARR寄存器-重装载寄存器
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
																													也可以由内部时钟加一个时钟分频而来,
																													分频系数就是由TIM_ClockDivision决定*/
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	//初始化OC-输出比较结构体
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//因为结构体里面的成员有些是高级定时器采用得到,所以这里就先全部初始化一遍,然后再配置具体的值
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	//TIM_OCInitStruct.TIM_Pulse = 50;//CRR   --舵机要求设置频率50HZ-即总时间20ms,高电平时间在0.5~2.5ms之间的PWM波型即CCR->500~2500
	TIM_OCInitStruct.TIM_Pulse = 0;//输出要求波型,这里的CRR就不需要了,用固件库的一个函数 TIM_SetCompare3 直接配置CRR
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性
	TIM_OC3Init(TIM2,&TIM_OCInitStruct);//CH3通道
	
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);
}
//0.5ms-0度   2.5ms-180度
//0度   	CCR=500
//180度   CCR=2500
//舵机设置角度,范围0~180
void Servo_SetAngle(float Angle)
{
	TIM_SetCompare3(TIM2,Angle*2000/180+500);
}


void PWM_SetCompare3(uint16_t Compare)//设置CRR
{
	TIM_SetCompare3(TIM2,Compare);
}
#include "stm32f10x.h"   // Device header
#include ".\tim\bsp_tim.h"
#include ".\KEY\bsp_key.h"
uint8_t KeyNum;
float Angle;

int main()
{
	KEY_GPIO_Config();
	LED_GPIO_Config();
	PWM_Config();
	
	while(1)
	{
		KeyNum = Key_Scan();
		if(KeyNum == 0)
		{
			Angle+=30;
			if(Angle>180)
			{
				Angle = 0;
			}
		}
		else if(KeyNum == 1)
		{
			Angle-=30;
			if(Angle<0)
			{
				Angle = 180;
			}
		}
		Servo_SetAngle(Angle);
	}
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/460528.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——物理层(奈氏准则和香农定理)

计算机网络——物理层&#xff08;奈氏准则和香农定理&#xff09; 失真码间串扰奈氏准则&#xff08;奈奎斯特定理&#xff09;极限数据率 噪声信噪比香农定理奈氏准则和香农定理的区别 前面我们已经了解一些数据通信的基本知识&#xff0c;没有看过上一篇得小伙伴可以点击这里…

2024最新小狐狸AI 免授权源码

后台安装步骤&#xff1a; 1、在宝塔新建个站点&#xff0c;php版本使用7.2 、 7.3 或 7.4&#xff0c;把压缩包上传到站点根目录&#xff0c;运行目录设置为/public 2、导入数据库文件&#xff0c;数据库文件是 /db.sql 3、修改数据库连接配置&#xff0c;配置文件是/.env 4、…

每日一题——LeetCode1684.统计一致字符串的数目

方法一 Set()双层for循环遍历 将allowd放入Set集合中&#xff0c;遍历words每一项的每一个字符看是否有allowd不含有的字符 var countConsistentStrings function(allowed, words) {let set new Set(allowed),count0for(let word of words){for(let char of word){if(!set.…

redis 入门01

1.安装与配置 在官网下压缩包并传送给自己的虚拟机或者使用wget直接下载都可以 注意:redis是运行在linux下的基于内存的kv键值对数据库 安装与配置参考 2.经典Hello World 注意设置redis在后台运行,默认是前台进行的 我们配置完成之后首先启动服务器 redis-server 配置文件 这里…

从混沌到秩序——90年代中国数据库的激烈角逐

引言 在数字化浪潮的推动下&#xff0c;数据库技术已成为支撑数字经济的坚实基石。腾讯云TVP《技术指针》联合《明说三人行》特别策划的直播系列——【中国数据库前世今生】&#xff0c;我们将通过五期直播&#xff0c;带您穿越五个十年&#xff0c;深入探讨每个时代的数据库演…

uniapp 跳转返回携带参数(超好用)

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.返回界面 uni.$emit(enterPeople, this.entryList)uni.navigateBack({delta: 1}) 2.返回到的界面&#xff08;接收数据界面&#xff09; onShow() {let that thisuni.$on(enterPeople,function(enterPeopledata){console.…

自习室预订系统|基于springboot框架+ Mysql+Java+B/S架构的自习室预订系统设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 学生功能模块 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参…

蓝桥真题——-小蓝重组质数(全排列和质数判断)

小蓝有一个十进制正整数n&#xff0c;其不包含数码0&#xff0c;现在小蓝可以任意打乱数码的顺序&#xff0c;小蓝想知道通过打乱数码顺序,n 可以变成多少个不同的质数。 #include <iostream> #include<bits/stdc.h> using namespace std; bool isprime(int n) {if…

51单片机LED8*8点阵显示坤坤跳舞打篮球画面

我们作为一名合格的 ikun&#xff0c;专业的小黑子&#xff0c;这个重要的知识必须学会。 先看效果&#xff1a; 51LED点阵_鸡你太美 这里我们首先要用到延时函数Delay&#xff1a; void Delay(unsigned int xms) {unsigned char i, j;while(xms--){ i 2;j 239;do{while (-…

NodeJs利用腾讯云实现手机发送验证码

本文介绍如何在nodejs实现短信发送&#xff0c;以腾讯云的短信验证为例。 腾讯云中准备工作 首先需要腾讯云的个人或者企业认证的账号&#xff0c;个人会赠送一百条&#xff0c;企业赠送一千条&#xff0c;可以用于测试&#xff0c;地址&#xff1a;腾讯云短信服务。然后需要…

计算点集的最小外接矩形——OpenCV的minAreaRect函数

计算点集的最小外接矩形——OpenCV的minAreaRect函数 函数原型 输入一系列二维点&#xff0c;返回其最小外接矩形。 RotatedRect minAreaRect( InputArray points );根据函数原型&#xff0c;输入的数据可以是vector<Point>类型&#xff0c;包含1个以上的点&#xff1…

Redis:ClassCastException【bug】

Redis&#xff1a;ClassCastException【bug】 前言版权Redis&#xff1a;ClassCastException【bug】错误产生相关资源控制器&#xff1a;UserController("/user")配置&#xff1a;RedisConfiguration实体类&#xff1a;User数据表&#xff1a;User 解决 最后 前言 2…

BMP280学习

1.Forced mode模式&#xff0c;单次采集后进入休眠&#xff0c;适用于低采样率。 2.normal mode模式&#xff0c;持续采集&#xff0c;我们使用这种 采集事件基本都是ms级&#xff0c;所以我们1s更新一次。 温度和压力的计算 #include <SPI.h> //定义数据类型 #define s3…

hadoop单机ssh免密登录

1. 在hadoop目录下生成密钥对 [rootmaster centos]# cd /usr/apps/hadoop-2.7.1/ [rootmaster hadoop-2.7.1]# ssh-keygen -t rsa //在hadoop目录下生成密钥对 2.找到密钥对的位置 [rootmaster hadoop-2.7.1]# find / -name .ssh //找到密钥对的位置 cd [rootmaster hadoo…

二进一出模拟量隔离变送器

二进一出模拟量隔离变送器定义&#xff1a; 是两路模拟量信号同时输入&#xff0c;隔离变送器选择其中的一路高信号输入的或者低信号输入的通道进行信号传输及控制&#xff0c;该隔离变送器可以用控制信号来选择A路&#xff0c;B路的输入信号&#xff0c;还可以通过干接点&…

【类和对象】类的作用域 | 类的实例化 | 类对象模型 | this指针

目录 5.类的作用域 6.类的实例化 6.1成员的声明和定义 6.2实例化出的对象大小 7.类对象模型❗❗ 7.1如何计算类对象的大小 7.2类对象的存储方式猜测 7.3结构体内存对齐规则 7.3.1内存对齐 7.3.2大小端 8.this指针 8.1this指针的引出 8.2this指针的特性 C和C实…

【四 (2)数据可视化之 Matplotlib 常用图表及代码实现 】

目录 文章导航一、介绍二、安装Matplotlib三、导入Matplotlib四、设置可以中文显示四、常用图形1、散点图&#xff08;Scatter Plot&#xff09;2.1、线性图&#xff08;Line Plot&#xff09;2.2、堆叠折线图2.3、多图例折线图3.1、柱状图/条形图&#xff08;Bar Chart&#x…

基于openCV实现的单目相机行人和减速带检测

概述 在计算机视觉项目中&#xff0c;相机标定是一项至关重要的任务&#xff0c;因为它可以校正相机内部参数&#xff0c;消除因镜头畸变等因素导致的图像失真&#xff0c;从而提高后续图像处理和分析的精度。在这个项目中&#xff0c;相机标定的核心功能集成在名为calibratio…

C++_学习String

1.标准库中的string类 1. 字符串是表示字符序列的类 2. 标准的字符串类提供了对此类对象的支持&#xff0c;其接口类似于标准字符容器的接口&#xff0c;但添加了专门用于操作单字节字符字符串的设计特性 3. string 类是使用 char( 即作为它的字符类型&#xff0c;使用它的默…

钡铼技术有限公司R40路由器工业4G让养殖环境监控更高效

钡铼技术有限公司的R40路由器是一款专为养殖环境监控而设计的工业级4G路由器。该路由器的出现极大地提高了养殖行业的监控效率&#xff0c;为养殖场主和管理者提供了更可靠、高效的解决方案。本文将从功能特点、优势以及应用案例等方面介绍钡铼技术有限公司的R40路由器在养殖环…