完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
用串口发送数据包,解码后:
1.改变PB5和PB6的PWM频率和占空比 2.使PA0输入捕获方波 3.相关信息返回串口 基于正点原子的stm32f103zet6 1.时钟配置: 2.TIM配置: TIM3ch2负责PB5,这里没画,但是一定要记得中断使能哦 TIM4ch1负责PB6,这里没画,但是一定要记得中断使能哦 TIM5用来输入捕获,这里没画,但是一定要记得中断使能哦 USART1 时钟树配置 提示: TIM中的auto-reload不管你是disable还是enable都无所谓 你发现我的TIM3和TIM4的prescale是0,我打算占空比这种东西配置又串口发送的数据包来配置。 工程配置 /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "stdbool.h" /* USER CODE END Includes */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET); #define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET); #define LED1_TOG() HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5); #define LED2_ON() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET); #define LED2_OFF() HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET); #define LED2_TOG() HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5); /* USER CODE END PD */ /* USER CODE BEGIN PV */ /*********01以下为调制PWM所需变量**************/ uint8_t str1[] ="hello worldrn"; uint8_t str2[] ="error datarn"; uint8_t Rx_data[1]; //串口接受到的数据 uint8_t buff[64] ="0x00";//串口准备发送数据的存放地点 int Duty =200; int Step =0; int flag =0; bool get_Flag2_Times =0; bool get_Flag3_Times =0; /*********02以下为输入捕获所需变量**************/ uint16_t capture_Buf[3] ={0}; //存放计数值 uint8_t capture_Cnt =0; //状态标志位 uint32_t overload_Cnt =0; //溢出次数 uint16_t high_time =0; //高电平捕获计数 uint16_t low_time =0; //低电平捕获计数 double HL_time =0; //高电平时间 double LL_time =0; //低电平时间 double fre =0; //频率 double duty =0; //占空比 /*************重写fputc函数*********************/ int fputc(int c, FILE *stream) { HAL_UART_Transmit(&huart1, (unsigned char *)&c, 1, 1000); return 1; } /* USER CODE END PV */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /************用户初始化相应的时钟配置****************/ void User_Init() { HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//PWM定时器3启动 HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);//PWM定时器4启动 HAL_UART_Receive_IT(&huart1,Rx_data,1); //串口准备接收中断 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//定时器5设置为上升沿捕获 HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //定时器5启动 //HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //输入捕获定时器 //HAL_TIM_Base_Start_IT(&htim4); //普通定时器4 } void getHelp() { printf("/************************************************/rn"); printf("欢迎使用stm32通信协议实验rn"); printf("串口输入数据包进行你想要的操作rn"); printf("数据包格式为FF FF CB 0x X1 X2 X3 X4....FFrn"); printf("其中FF FF为包头,FF为包尾rn"); printf("CB表示上位机向下位机发送数据rn"); printf("0x为操作码,其中01调制占空比,02调制周期,03捕获方波rn"); printf("默认方波输出GPIO为PB5和PE5,方波捕获GPIO为PA0rn"); printf("0x为01时,X1,X2控制PB5输出高电平时长的低8位和高8位rn"); printf("X3,X4控制PE5输出高电平时长的低8位和高8位rn"); printf("0x为02时,X1,X2控制PB5输出周期时长的低8位和高8位rn"); printf("X3,X4控制PE5输出周期时长的低8位和高8位rn"); printf("单位是usrn"); printf("0x为03时,无视Xi的取值,PA0读取方波rn"); printf("/************************************************/rn"); printf("初始时,设置PB5,PE5周期为20msrn"); printf("示例:"FF FF CB 01 D0 07 F4 01 FF"设置PB5,PE5高电平为2ms,0.5msrn"); printf("示例:"FF FF CB 02 20 4E 20 4E FF"设置PB5,PE5周期为20msrn"); printf("示例:"FF FF CB 03 FF"输出PA0捕获到的方波rn"); printf("/************************************************/rn"); } /*通过data[0]来改变PWM最大占空比的周期(不得大于200即C8) 此函数用于早期调试,本例程并没有用到*/ void PWM_Breathe_LED1(uint8_t *Rx_data) { //Duty指的是高电平的时间,而高电平时灯是灭的。Duty=0时,灯最亮 for(Duty=Rx_data[0];Duty>=0;Duty--) { __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Duty); HAL_Delay(1); } for(Duty=0;Duty<=Rx_data[0];Duty++) { __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Duty); HAL_Delay(1); } } /*此函数用于调制PB5的占空比 其中*Rx_data代表第八位,*(Rx_data+1)代表高八位*/ void PWM_SG90_1(uint8_t *Rx_data) { Duty=*(Rx_data) + 256 * (*(Rx_data+1)); //下面这里用printf更好,但是这个函数是早期写的,不太想改 uint8_t temp[64]=" "; sprintf((char*)temp,"PB5的数值是:%d, 占空比为:%.2f/%.2fmsrn",Duty,Duty/1000.0,(htim3.Init.Period+1)/1000.0);//Duty的数值是: HAL_UART_Transmit(&huart1,temp,sizeof(temp),10000); //上面这里用printf更好,但是这个函数是早期写的,不太想改 HAL_UART_Receive_IT(&huart1,Rx_data,1); __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,Duty); } /*此函数用于调制PE5的占空比*/ void PWM_SG90_2(uint8_t *Rx_data) { Duty=*(Rx_data) + 256 * (*(Rx_data+1)); //下面这里用printf更好,但是这个函数是早期写的,不太想改 uint8_t temp[64]=" "; sprintf((char*)temp,"PE5的数值是:%d, 占空比为:%.2f/%.2fmsrn",Duty,Duty/1000.0,(htim4.Init.Period+1)/1000.0);//Duty的数值是: HAL_UART_Transmit(&huart1,temp,sizeof(temp),10000); //上面这里用printf更好,但是这个函数是早期写的,不太想改 HAL_UART_Receive_IT(&huart1,Rx_data,1); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,Duty); } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ Rx_data[0]=0xC8;//初始时,高电平时长最大值按照200来看 /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM3_Init(); MX_USART1_UART_Init(); MX_TIM4_Init(); MX_TIM5_Init(); /* USER CODE BEGIN 2 */ /************用户初始化相应的时钟配置****************/ User_Init(); printf("欢迎使用stm32通信协议实验rn"); printf("输入"FF FF CB 00 FF"以获取帮助rn"); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ } /* USER CODE END 3 */ } * USER CODE BEGIN 4 */ /* 获得数据包后,根据包头进行指令解码 */ void takeActions(uint8_t* low,uint8_t* high) { //*low为CB表示上位机是向下位机发送指令,*high为01表示动作调试指令(调制高电平时间) //一般来讲*low为buff[2],*high为buff[3] if(*low == 0xCB && *high == 0x01) { //其中buff[4]为低8位buff[5]为高8位 if(buff[4]!=0x00) { PWM_SG90_1(&buff[4]);//buff[4]和buff[5]为输出占空比。 } //其中buff[6]为低8位buff[7]为高8位 if(buff[6]!=0x00) { PWM_SG90_2(&buff[6]);//buff[6]和buff[7]为输出占空比。 } } //low为CB表示上位机是向下位机发送指令,high为02表示动作调试指令(调试周期长短) if(*low == 0xCB && *high == 0x02) { if(buff[4]!=0x00) { htim3.Init.Period=buff[4]+256*buff[5]; uint8_t temp[64]=" "; sprintf((char*)temp,"PB5接收到的数据为%d,单个周期为%.4fmsrn",htim3.Init.Period,(htim3.Init.Period+1)/1000.0); HAL_UART_Transmit(&huart1,temp,sizeof(temp),10000); HAL_UART_Receive_IT(&huart1,Rx_data,1); } if(buff[6]!=0x00) { htim4.Init.Period=buff[6]+256*buff[7]; uint8_t temp[64]=" "; sprintf((char*)temp,"PE5接收到的数据为%d,单个周期为%.4fmsrn",htim4.Init.Period,(htim4.Init.Period+1)/1000.0); HAL_UART_Transmit(&huart1,temp,sizeof(temp),10000); HAL_UART_Receive_IT(&huart1,Rx_data,1); } } //low为CB表示上位机是向下位机发送指令,high为03表示动作调试指令(PA0输入捕获检测周期长短) if(*low == 0xCB && *high == 0x03) { printf("PA0捕获频率: %7.3lfhz,占空比:%4.1lf%%rn高电平时长:%7.3lfms,低电平时长:%7.3lfmsrn周期:%7.3lfmsrnrn",fre,duty,HL_time,LL_time,HL_time+LL_time); } if(*low == 0xCB && *high == 0x00) { getHelp(); } } //捕获计数器溢出 中断回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance==TIM5) { overload_Cnt++; } } //捕获计数器捕获到边沿 中断回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(TIM5 == htim->Instance) { switch(capture_Cnt){ //初始化已经为上升沿检测,此时捕获到上升沿后,进入case 0 case 0: capture_Buf[0]=HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值. __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置为下降沿捕获 capture_Cnt++; overload_Cnt=0;//准备为溢出中断计数 break; case 1: capture_Buf[1]=HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值. __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置为上升沿捕获 capture_Cnt++; break; case 2: capture_Buf[2]=HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//获取当前的捕获值. HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); //停止捕获 high_time=capture_Buf[1]-capture_Buf[0] + overload_Cnt*0xffff; low_time=capture_Buf[2]-capture_Buf[1] + overload_Cnt*0xffff; HL_time=high_time * 0.01 ; LL_time=low_time * 0.01 ; fre=1/(HL_time+LL_time) * 1000; duty=HL_time/(HL_time+LL_time)*100; capture_Cnt=0;//clear flag overload_Cnt=0;//clear flag __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置为上升沿捕获 HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //Start input capture break; } } } //串口1中断回调 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { //HAL_UART_Transmit(&huart1,Rx_data,sizeof(Rx_data),10000);//发送我接受到的数据 //先判断是否是包头包尾数据 if(Rx_data[0]==0xFF) { switch(flag) { case 0 ://如果是第一次接受到包头,flag置为1 { flag=1; break; } case 1 ://如果是第二次收到包头,flag置为2,重置buff内的数据, { flag=2; memset(buff, 0, sizeof(buff)); buff[0]=0xFF; buff[1]=0xFF; Step=2;//为后续添加数据做准备 get_Flag2_Times=1; break; } case 2: //如果是第三次次收到包尾,flag置为3 { flag=3; buff[Step]=0xFF; get_Flag3_Times=1; break; } } } //第一次flag=2不能进入,第二次到flag=2可以进入 if(flag==2 && get_Flag2_Times!=1) { buff[Step]=Rx_data[0]; Step++; } //如果已经获得包尾标志, if(flag==3 && get_Flag3_Times==1)//包尾数据如果是flag=3,数据接受完毕 { flag=0; //HAL_UART_Transmit(&huart1,buff,Step+1,10000); takeActions(&buff[2],&buff[3]); } } get_Flag2_Times=0; get_Flag3_Times=0; HAL_UART_Receive_IT(&huart1,Rx_data,1);//接受1个字节数据,改变Rx_data[0]的数值 } //定时器4中断回调 //void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //{ // if(htim->Instance==TIM4) // { // //LED2_TOG(); // } //} /* USER CODE END 4 */ |
|
|
|
只有小组成员才能发言,加入小组>>
3323 浏览 9 评论
3000 浏览 16 评论
3498 浏览 1 评论
9073 浏览 16 评论
4093 浏览 18 评论
1194浏览 3评论
614浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2342浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1902浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 15:27 , Processed in 1.359431 second(s), Total 78, Slave 57 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号