文章目录[隐藏]
目录
第一步,官网下载https://www.keil.com/. 3
/* DMA1 channel1 configuration*///DMA配置... 12
/* ADC1 configuration*//ADC配置... 13
KEIL5下载、安装
第一步,官网下载Keil Embedded Development Tools for Arm, Cortex-M, Cortex-R4, 8051, C166, and 251 processor families.
St官网
STM32 GPIO配置
构造结构体
GPIO_InitTypeDef GPIO_InitStructure;
对于引脚一定要配置对应时钟使能
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
开启GPIO时钟,选择GPIOC引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//选择13号引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//选择输出速度10MHZ
引脚输出模式
//选择输出方式推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure );//对于GPIOC进行结构体构造
GPIO_ResetBits(GPIOC,GPIO_Pin_13);//给GPIOC 13号引脚拉低电平
GPIO_SetBits(GPIOC,GPIO_Pin_13);//给GPIOC 13号引脚拉高电平
STM时间延迟配置
法一:for循环
解析:用for循环递加变量,
不足:循环时间固定,for循环期间不能处理别的判断等、时间不精准。
void Delay_ms(u16 time)
{
unsigned int n ;
while(time>0)
{
for (n =0;n<1000;n++)
{
Delay_us(1);
}
time--;
}
}
法二:__NOP()空语句循环
解析:_nop()是STM32执行一句空语句,根据主频72MHZ进行计算,每执行72条_nop()执行时间是1ms,时间更精准。
不足:循环期间不能处理别的判断等。
void Delay_us(u16 time)
{
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
法三:STM32 滴答定时器
解析:滴答定时器采用中断的方式,计时最精准,在操作期间可以进行其他判断。
不足:可能会被其他中断干扰,响应不及时。
void SysTick_Handler(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
void SysTick_Init( void )
{
if(SysTick_Config(72000))
{
while(1);
}
}
void Delay_ms(uint16_t nTime)
{
TimingDelay = nTime;
//使能系统滴答定时器
while(TimingDelay !=0);
}
STM32 串口通信
USART简介:
USART:通用同步异步收发器,是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
引脚连接方法:(反接)
RXD:数据输入引脚,数据接受;
TXD:数据发送引脚,数据发送。
编程较多使用固件库USART.C
配置代码解析:
USART1_Config();
//USART配置函数的主要作用是打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式,以便信息的传输与接收。
NVIC_USART1_Config();
//配置串口中断优先级,打开相应的串口接收中断,中断接收函数的参数
串口发送代码解析:
串口发送需先导入"string.h"头文件,调用sprintf()函数将发送的数据以对应格式存进数组,再调用USART_OUT()函数输出数组。
//将字符格式化进数组
sprintf(str,"%d",value);
//串口输出函数
USART_OUT(USART1,(uint8_t *)str,strlen(str));
串口接收代码解析:
串口接收的问题在于判断上位机的数据发送完毕并成功接收下来。
方法:可以将串口接收的数据分别存入接收的数组,法一可以采取数据末尾添加接收符的方法来判断发送结束,但现实中不存在结束符,法二在接收过程中添加计时器,通过判断计时器和数组长度来判断接收完毕。
void USART1_IRQHandler(void) //串口1 中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
//判断读寄存器是否非空
{
res=USART_ReceiveData(USART1);
buffer[i]=res;
//将串口一接收的数据存进数组
i++;
ck_TimingDelay=10;
//利用自定义串口计时器和数组长度来判断接收是否完毕
}
}
串口定时器:
if (ck_TimingDelay != 0x00)
{
ck_TimingDelay--;
}
ADC电平采集
ADC简介
ADC是指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
DMA简介
DMA即直接存储器访问,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。
代码解析:
void GPIO_Configuration(void)//引脚配置函数
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//使用PA5引脚,ADC_Channel_5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
RCC_Configuration();//时钟配置
GPIO_Configuration();//引脚配置
/* DMA1 channel1 configuration*///DMA配置
DMA_DeInit(DMA1_Channel1);//初始化DMA
//设置DMA传输外设地址
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
//设置内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据传输方向
DMA_InitStructure.DMA_BufferSize = 2;//传输数据大小
//外设地址不变还是递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//内存地址是否递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//设置字节传输数据长度
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
//设置内存数据长度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设置DMA模式循环
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA通道优先级
//设置是否是存储器到存储器模式传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);//设置DMA
/* ADC1 configuration*//ADC配置
// ADC 工作模式选择
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent
// ADC 扫描(多通道)或者单次(单通道)模式选择
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
// ADC 单次转换或者连续转换选择
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ADC 转换触发信号选择
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// ADC 数据寄存器对齐格式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ADC 采集通道数
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_55Cycles5);// 配置ADC通道转换顺序和时间
注:如需多通道采集ADC数据,需要更改引脚配置,DMA传输数据大小,DMA内存地址递增,ADC采集通道数和ADC通道顺序这些参数。
PWM脉宽调制
PWM简介
脉宽调制(PWM)是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。
占空比定义:占空比就是高电平所占整个周期的时间,如下图所示:
代码解析:
void GPIO_Configuration(void)//引脚代码配置
{//TIM3的1、2、3、4通道分别是PA6、PA7,PB0、PB1.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复合推挽模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//时钟配置
RCC_Configuration();
//引脚配置
GPIO_Configuration();
//计算预分频器值
PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
/* 通用定时器配置*/
TIM_TimeBaseStructure.TIM_Period = 665;//总周期时间
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;//分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:
//向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//初始化
/* PWM1模式配置:信道1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM模式1
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;//高电平占比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
修改CCR1_Val来控制占空比
TIM_SetCompare1(TIM3,CCR1_Val);
步科组态屏
MODBUS协议概述:
Modbus是一个请求/应答协议,并且提供功能码规定的服务。
Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和对答的方式,数据通信采用Maser(主站)/Slave(从站)方式,主站发出数据请求消息,从站接收到正确消息后就可以发送数据到主站以相应请求;主站也可以直接发消息修改从站的数据,实现双向读写。
功能码:
在HMI系统中,常用的功能码如下:
CRC校验:
循环冗余校验(CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。
CRC校验流程分析:
1.置16位寄存器为全1,作为CRC寄存器。
2.把一个8位数据与16位CRC寄存器的低字节相异或,把结果放于CRC寄存器中。
3.把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位(移出位)。
4.如果最低位为0,重复2.3(再移位);如果最低位为1,CRC寄存器与多项式A001H(1010 0000 0000 0001)进行异或。
5.重复2.3、2.4,直到右移8次,这样整个8位数据全部进行了处理。
6.重复2-5,进行下一个8位数据的处理。
7.将一帧的所有数据字节处理完后得到CRC-16寄存器。
8.将CRC-16寄存器的低字节和高字节交换,得到的值即为CRC-16码。
CRC代码:
unsigned short CRC16_Modbus ( unsigned char *pdata, int len)
{
unsigned short crc=0xFFFF;
int i, j;
for (j=0;j<len;j++)
{
crc=crc^pdata[j];
for (i=0;i<8;i++)
{
if((crc&0x0001) >0)
{
crc=crc>>1;
crc=crc^ 0xa001;
}
else
crc=crc>>1;
}
}
return crc;
(1)01功能码应用
举例:
int Function01()
{
buffer1[0]=buffer[0];//站号01
buffer1[1]=buffer[1];//功能码01
buffer1[2]=0x01;//字节数
buffer1[3]=0x03;//二进制011
width_t crc = CRC16_Modbus(buffer1, 4);//CRC校验码
buffer1[4] = (char)crc;//取校验码的低八位
buffer1[5] = (char)(crc >> 8);//取校验码的高八位
USART_OUT(USART1,buffer1,6);
return 0;
}
(2)03功能码应用
注:读取的数据要分成高低两个字节,从机响应字节数会在主机请求的字节数乘2,向左位移一位即可。
举例:
int Function03()
{
buffer3[0]=buffer[0];//站号01
buffer3[1]=buffer[1];//功能码03
if(buffer[4]==0x00) buffer3[2]=(buffer[5]<<1);//数据字节数*2,分高低字节
buffer3[4] = (char)CCR1_Val;//PWM占空比低八位
buffer3[3] = (char)(CCR1_Val >> 8);//PWM占空比高八位
width_t crc = CRC16_Modbus(buffer3, 5);//CRC校验码
buffer3[5] = (char)crc;//取校验码的低八位
buffer3[6] = (char)(crc >> 8);//取校验码的高八位
USART_OUT(USART1,buffer3,7);
return 0;
}
(3)05功能码应用
注:“位状态设定”元件会持续请求01码来查询按键状态,在按下时才会发送05码。主机请求和从机发送是相同的,要在从机程序中改变状态。
举例:
int Function05()
{
if(y==0)
{
CCR1_Val=CCR1_Val+50; //改变PWM占空比(+)
USART_OUT(USART1,buffer,8);//返回相同数据
}
else if(y==1)
{
CCR1_Val=CCR1_Val-50;//改变PWM占空比(—)
USART_OUT(USART1,buffer,8); //返回相同数据
}
return 0;
}
版权声明:本文为CSDN博主「陈苏棠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47359357/article/details/121901377
目录
第一步,官网下载https://www.keil.com/. 3
/* DMA1 channel1 configuration*///DMA配置... 12
/* ADC1 configuration*//ADC配置... 13
KEIL5下载、安装
第一步,官网下载Keil Embedded Development Tools for Arm, Cortex-M, Cortex-R4, 8051, C166, and 251 processor families.
St官网
STM32 GPIO配置
构造结构体
GPIO_InitTypeDef GPIO_InitStructure;
对于引脚一定要配置对应时钟使能
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
开启GPIO时钟,选择GPIOC引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;//选择13号引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//选择输出速度10MHZ
引脚输出模式
//选择输出方式推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure );//对于GPIOC进行结构体构造
GPIO_ResetBits(GPIOC,GPIO_Pin_13);//给GPIOC 13号引脚拉低电平
GPIO_SetBits(GPIOC,GPIO_Pin_13);//给GPIOC 13号引脚拉高电平
STM时间延迟配置
法一:for循环
解析:用for循环递加变量,
不足:循环时间固定,for循环期间不能处理别的判断等、时间不精准。
void Delay_ms(u16 time)
{
unsigned int n ;
while(time>0)
{
for (n =0;n<1000;n++)
{
Delay_us(1);
}
time--;
}
}
法二:__NOP()空语句循环
解析:_nop()是STM32执行一句空语句,根据主频72MHZ进行计算,每执行72条_nop()执行时间是1ms,时间更精准。
不足:循环期间不能处理别的判断等。
void Delay_us(u16 time)
{
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
法三:STM32 滴答定时器
解析:滴答定时器采用中断的方式,计时最精准,在操作期间可以进行其他判断。
不足:可能会被其他中断干扰,响应不及时。
void SysTick_Handler(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
void SysTick_Init( void )
{
if(SysTick_Config(72000))
{
while(1);
}
}
void Delay_ms(uint16_t nTime)
{
TimingDelay = nTime;
//使能系统滴答定时器
while(TimingDelay !=0);
}
STM32 串口通信
USART简介:
USART:通用同步异步收发器,是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
引脚连接方法:(反接)
RXD:数据输入引脚,数据接受;
TXD:数据发送引脚,数据发送。
编程较多使用固件库USART.C
配置代码解析:
USART1_Config();
//USART配置函数的主要作用是打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式,以便信息的传输与接收。
NVIC_USART1_Config();
//配置串口中断优先级,打开相应的串口接收中断,中断接收函数的参数
串口发送代码解析:
串口发送需先导入"string.h"头文件,调用sprintf()函数将发送的数据以对应格式存进数组,再调用USART_OUT()函数输出数组。
//将字符格式化进数组
sprintf(str,"%d",value);
//串口输出函数
USART_OUT(USART1,(uint8_t *)str,strlen(str));
串口接收代码解析:
串口接收的问题在于判断上位机的数据发送完毕并成功接收下来。
方法:可以将串口接收的数据分别存入接收的数组,法一可以采取数据末尾添加接收符的方法来判断发送结束,但现实中不存在结束符,法二在接收过程中添加计时器,通过判断计时器和数组长度来判断接收完毕。
void USART1_IRQHandler(void) //串口1 中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
//判断读寄存器是否非空
{
res=USART_ReceiveData(USART1);
buffer[i]=res;
//将串口一接收的数据存进数组
i++;
ck_TimingDelay=10;
//利用自定义串口计时器和数组长度来判断接收是否完毕
}
}
串口定时器:
if (ck_TimingDelay != 0x00)
{
ck_TimingDelay--;
}
ADC电平采集
ADC简介
ADC是指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。
DMA简介
DMA即直接存储器访问,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。
代码解析:
void GPIO_Configuration(void)//引脚配置函数
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//使用PA5引脚,ADC_Channel_5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
RCC_Configuration();//时钟配置
GPIO_Configuration();//引脚配置
/* DMA1 channel1 configuration*///DMA配置
DMA_DeInit(DMA1_Channel1);//初始化DMA
//设置DMA传输外设地址
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
//设置内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据传输方向
DMA_InitStructure.DMA_BufferSize = 2;//传输数据大小
//外设地址不变还是递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//内存地址是否递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//设置字节传输数据长度
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
//设置内存数据长度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设置DMA模式循环
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA通道优先级
//设置是否是存储器到存储器模式传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);//设置DMA
/* ADC1 configuration*//ADC配置
// ADC 工作模式选择
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent
// ADC 扫描(多通道)或者单次(单通道)模式选择
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
// ADC 单次转换或者连续转换选择
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ADC 转换触发信号选择
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// ADC 数据寄存器对齐格式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ADC 采集通道数
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_55Cycles5);// 配置ADC通道转换顺序和时间
注:如需多通道采集ADC数据,需要更改引脚配置,DMA传输数据大小,DMA内存地址递增,ADC采集通道数和ADC通道顺序这些参数。
PWM脉宽调制
PWM简介
脉宽调制(PWM)是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。
占空比定义:占空比就是高电平所占整个周期的时间,如下图所示:
代码解析:
void GPIO_Configuration(void)//引脚代码配置
{//TIM3的1、2、3、4通道分别是PA6、PA7,PB0、PB1.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复合推挽模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//时钟配置
RCC_Configuration();
//引脚配置
GPIO_Configuration();
//计算预分频器值
PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
/* 通用定时器配置*/
TIM_TimeBaseStructure.TIM_Period = 665;//总周期时间
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;//分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:
//向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//初始化
/* PWM1模式配置:信道1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM模式1
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;//高电平占比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
修改CCR1_Val来控制占空比
TIM_SetCompare1(TIM3,CCR1_Val);
步科组态屏
MODBUS协议概述:
Modbus是一个请求/应答协议,并且提供功能码规定的服务。
Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和对答的方式,数据通信采用Maser(主站)/Slave(从站)方式,主站发出数据请求消息,从站接收到正确消息后就可以发送数据到主站以相应请求;主站也可以直接发消息修改从站的数据,实现双向读写。
功能码:
在HMI系统中,常用的功能码如下:
CRC校验:
循环冗余校验(CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。
CRC校验流程分析:
1.置16位寄存器为全1,作为CRC寄存器。
2.把一个8位数据与16位CRC寄存器的低字节相异或,把结果放于CRC寄存器中。
3.把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位(移出位)。
4.如果最低位为0,重复2.3(再移位);如果最低位为1,CRC寄存器与多项式A001H(1010 0000 0000 0001)进行异或。
5.重复2.3、2.4,直到右移8次,这样整个8位数据全部进行了处理。
6.重复2-5,进行下一个8位数据的处理。
7.将一帧的所有数据字节处理完后得到CRC-16寄存器。
8.将CRC-16寄存器的低字节和高字节交换,得到的值即为CRC-16码。
CRC代码:
unsigned short CRC16_Modbus ( unsigned char *pdata, int len)
{
unsigned short crc=0xFFFF;
int i, j;
for (j=0;j<len;j++)
{
crc=crc^pdata[j];
for (i=0;i<8;i++)
{
if((crc&0x0001) >0)
{
crc=crc>>1;
crc=crc^ 0xa001;
}
else
crc=crc>>1;
}
}
return crc;
(1)01功能码应用
举例:
int Function01()
{
buffer1[0]=buffer[0];//站号01
buffer1[1]=buffer[1];//功能码01
buffer1[2]=0x01;//字节数
buffer1[3]=0x03;//二进制011
width_t crc = CRC16_Modbus(buffer1, 4);//CRC校验码
buffer1[4] = (char)crc;//取校验码的低八位
buffer1[5] = (char)(crc >> 8);//取校验码的高八位
USART_OUT(USART1,buffer1,6);
return 0;
}
(2)03功能码应用
注:读取的数据要分成高低两个字节,从机响应字节数会在主机请求的字节数乘2,向左位移一位即可。
举例:
int Function03()
{
buffer3[0]=buffer[0];//站号01
buffer3[1]=buffer[1];//功能码03
if(buffer[4]==0x00) buffer3[2]=(buffer[5]<<1);//数据字节数*2,分高低字节
buffer3[4] = (char)CCR1_Val;//PWM占空比低八位
buffer3[3] = (char)(CCR1_Val >> 8);//PWM占空比高八位
width_t crc = CRC16_Modbus(buffer3, 5);//CRC校验码
buffer3[5] = (char)crc;//取校验码的低八位
buffer3[6] = (char)(crc >> 8);//取校验码的高八位
USART_OUT(USART1,buffer3,7);
return 0;
}
(3)05功能码应用
注:“位状态设定”元件会持续请求01码来查询按键状态,在按下时才会发送05码。主机请求和从机发送是相同的,要在从机程序中改变状态。
举例:
int Function05()
{
if(y==0)
{
CCR1_Val=CCR1_Val+50; //改变PWM占空比(+)
USART_OUT(USART1,buffer,8);//返回相同数据
}
else if(y==1)
{
CCR1_Val=CCR1_Val-50;//改变PWM占空比(—)
USART_OUT(USART1,buffer,8); //返回相同数据
}
return 0;
}
版权声明:本文为CSDN博主「陈苏棠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47359357/article/details/121901377
暂无评论