完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
-----时隔一日,本次在上一次的代码中加入了一点小技巧。这个项目中有两个电机驱动器设置为6400脉冲一圈,而且电机带了64减速箱,所以需要640064个脉冲才能让电机转一圈,如果按照上一次的做法,让电机转一圈至少需要在单片机开辟640064*2个16位的空间,贼恐怖的内存占用量。
----- 但是这两个电机不需要调速,而且速度固定,一个电机为另外一个电机转速的1/2,通过小技巧来修改下程序,最终使用了200+100个16位的空间来存储这些数据。 1 问题与解决方法 1.1 存储空间 问题1:如何减少存储空间 减少存储空间需要减少数组的大小,由于使用输出比较模式,就算是周期和占空比一样的脉冲,CCRX的值也要随时变化 解决方法: 1、仔细分析该模会发现定时器计数到设定最大值就会溢出,例如CCRX的增量值为10,定时器设置最大值为100,定时器计算到100的时候会溢出变成0,然后从0开始计数,利用这个规律,假如我把增量设置为5,数组设置为200,那么定时器计数最大值应该设置为1000,定时器就能从0计数到1000,然后溢出又从0开始。 2、通过1的方法就可以使用数组那200个值循环发送,这个时候需要配置DMA为循环模式,CubeMX的配置如下图所示。 问题2:如何控制脉冲数量 解决方法: 这个时候打开了DMA中断和定时器通道后,DMA每次发送完数组那200个数据就会进入一次发送完成中断并且重新将数组的值从第一个元素开始发送给CCRX。这个时候可以使用一个变量,在每次进入该通道的中断就加一,等到该变量与设定数值匹配就关闭DMA和定时器通道。但是这样的脉冲数量只能以200为单位,在实际项目中合理地设置这些参数。 总的来说,数组空间小,消耗内存小,DMA中断更频繁。 2 部分程序 数组和定时器 #define step1_speed_buf_size 200 #define step2_speed_buf_size step1_speed_buf_size/2 #define step3_speed_buf_size step1_speed_buf_size/2 //递增5 __IO u16 step1_speed_buf[step1_speed_buf_size]={ 0x0005, 0x000A, 0x000F, 0x0014, 0x0019, 0x001E, 0x0023, 0x0028, 0x002D, 0x0032, 0x0037, 0x003C, 0x0041, 0x0046, 0x004B, 0x0050, 0x0055, 0x005A, 0x005F, 0x0064, 0x0069, 0x006E, 0x0073, 0x0078, 0x007D, 0x0082, 0x0087, 0x008C, 0x0091, 0x0096, 0x009B, 0x00A0, 0x00A5, 0x00AA, 0x00AF, 0x00B4, 0x00B9, 0x00BE, 0x00C3, 0x00C8, 0x00CD, 0x00D2, 0x00D7, 0x00DC, 0x00E1, 0x00E6, 0x00EB, 0x00F0, 0x00F5, 0x00FA, 0x00FF, 0x0104, 0x0109, 0x010E, 0x0113, 0x0118, 0x011D, 0x0122, 0x0127, 0x012C, 0x0131, 0x0136, 0x013B, 0x0140, 0x0145, 0x014A, 0x014F, 0x0154, 0x0159, 0x015E, 0x0163, 0x0168, 0x016D, 0x0172, 0x0177, 0x017C, 0x0181, 0x0186, 0x018B, 0x0190, 0x0195, 0x019A, 0x019F, 0x01A4, 0x01A9, 0x01AE, 0x01B3, 0x01B8, 0x01BD, 0x01C2, 0x01C7, 0x01CC, 0x01D1, 0x01D6, 0x01DB, 0x01E0, 0x01E5, 0x01EA, 0x01EF, 0x01F4, 0x01F9, 0x01FE, 0x0203, 0x0208, 0x020D, 0x0212, 0x0217, 0x021C, 0x0221, 0x0226, 0x022B, 0x0230, 0x0235, 0x023A, 0x023F, 0x0244, 0x0249, 0x024E, 0x0253, 0x0258, 0x025D, 0x0262, 0x0267, 0x026C, 0x0271, 0x0276, 0x027B, 0x0280, 0x0285, 0x028A, 0x028F, 0x0294, 0x0299, 0x029E, 0x02A3, 0x02A8, 0x02AD, 0x02B2, 0x02B7, 0x02BC, 0x02C1, 0x02C6, 0x02CB, 0x02D0, 0x02D5, 0x02DA, 0x02DF, 0x02E4, 0x02E9, 0x02EE, 0x02F3, 0x02F8, 0x02FD, 0x0302, 0x0307, 0x030C, 0x0311, 0x0316, 0x031B, 0x0320, 0x0325, 0x032A, 0x032F, 0x0334, 0x0339, 0x033E, 0x0343, 0x0348, 0x034D, 0x0352, 0x0357, 0x035C, 0x0361, 0x0366, 0x036B, 0x0370, 0x0375, 0x037A, 0x037F, 0x0384, 0x0389, 0x038E, 0x0393, 0x0398, 0x039D, 0x03A2, 0x03A7, 0x03AC, 0x03B1, 0x03B6, 0x03BB, 0x03C0, 0x03C5, 0x03CA, 0x03CF, 0x03D4, 0x03D9, 0x03DE, 0x03E3, 0 }; //递增10 __IO u16 step2_speed_buf[step2_speed_buf_size]={ 0x000A, 0x0014, 0x001E, 0x0028, 0x0032, 0x003C, 0x0046, 0x0050, 0x005A, 0x0064, 0x006E, 0x0078, 0x0082, 0x008C, 0x0096, 0x00A0, 0x00AA, 0x00B4, 0x00BE, 0x00C8, 0x00D2, 0x00DC, 0x00E6, 0x00F0, 0x00FA, 0x0104, 0x010E, 0x0118, 0x0122, 0x012C, 0x0136, 0x0140, 0x014A, 0x0154, 0x015E, 0x0168, 0x0172, 0x017C, 0x0186, 0x0190, 0x019A, 0x01A4, 0x01AE, 0x01B8, 0x01C2, 0x01CC, 0x01D6, 0x01E0, 0x01EA, 0x01F4, 0x01FE, 0x0208, 0x0212, 0x021C, 0x0226, 0x0230, 0x023A, 0x0244, 0x024E, 0x0258, 0x0262, 0x026C, 0x0276, 0x0280, 0x028A, 0x0294, 0x029E, 0x02A8, 0x02B2, 0x02BC, 0x02C6, 0x02D0, 0x02DA, 0x02E4, 0x02EE, 0x02F8, 0x0302, 0x030C, 0x0316, 0x0320, 0x032A, 0x0334, 0x033E, 0x0348, 0x0352, 0x035C, 0x0366, 0x0370, 0x037A, 0x0384, 0x038E, 0x0398, 0x03A2, 0x03AC, 0x03B6, 0x03C0, 0x03CA, 0x03D4, 0x03DE, 0 }; __IO u16 step3_speed_buf[step3_speed_buf_size]={ 0x000A, 0x0014, 0x001E, 0x0028, 0x0032, 0x003C, 0x0046, 0x0050, 0x005A, 0x0064, 0x006E, 0x0078, 0x0082, 0x008C, 0x0096, 0x00A0, 0x00AA, 0x00B4, 0x00BE, 0x00C8, 0x00D2, 0x00DC, 0x00E6, 0x00F0, 0x00FA, 0x0104, 0x010E, 0x0118, 0x0122, 0x012C, 0x0136, 0x0140, 0x014A, 0x0154, 0x015E, 0x0168, 0x0172, 0x017C, 0x0186, 0x0190, 0x019A, 0x01A4, 0x01AE, 0x01B8, 0x01C2, 0x01CC, 0x01D6, 0x01E0, 0x01EA, 0x01F4, 0x01FE, 0x0208, 0x0212, 0x021C, 0x0226, 0x0230, 0x023A, 0x0244, 0x024E, 0x0258, 0x0262, 0x026C, 0x0276, 0x0280, 0x028A, 0x0294, 0x029E, 0x02A8, 0x02B2, 0x02BC, 0x02C6, 0x02D0, 0x02DA, 0x02E4, 0x02EE, 0x02F8, 0x0302, 0x030C, 0x0316, 0x0320, 0x032A, 0x0334, 0x033E, 0x0348, 0x0352, 0x035C, 0x0366, 0x0370, 0x037A, 0x0384, 0x038E, 0x0398, 0x03A2, 0x03AC, 0x03B6, 0x03C0, 0x03CA, 0x03D4, 0x03DE, 0 }; 定时器的配置只给出初始化的,其他的和上一篇文章一样 htim1.Instance = TIM1; htim1.Init.Prescaler = 71; //设置脉冲频率 htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 1000; //这个值根据数值的大小和增量设置 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_OC_Init(&htim1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } 步进电机驱动程序 下面是步进电机的配置 //电机x typedef enum { step_motor1, step_motor2, step_motor3, }STEP_MOTORX_TypeDef; //方向 typedef enum { cw, ccw, }DIR_TypeDef; //使能 typedef enum { DIS, EN, }EN_TypeDef; void set_motor_run(STEP_MOTORX_TypeDef step_motorx,DIR_TypeDef dir,u32 position,EN_TypeDef state); /** * 函数功能: 设置步进电机 * 输入参数: setp_motorx:电机x * dir:方向 * position:设置位置 * state:使能 * 返 回 值: 无 * 说 明: */ void set_motor_run(STEP_MOTORX_TypeDef step_motorx,DIR_TypeDef dir,u32 position,EN_TypeDef state) { step_prmt[step_motorx].set_en=state; //使能和失能 if(state==DIS) { step_prmt[step_motorx].set_pos=0; //失能电机 if(step_motorx==step_motor1) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_2); //关闭DMA通道和定时器通道2 STEP1_DIS; } else if(step_motorx==step_motor2) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_2); //关闭DMA通道和定时器通道3 STEP2_DIS; } else if(step_motorx==step_motor3) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_2); //关闭DMA通道和定时器通道4 STEP3_DIS; } } else { //初始化参数 step_prmt[step_motorx].set_dir=dir; step_prmt[step_motorx].set_pos=position; step_prmt[step_motorx].cur_pos=0; //启动定时器中断和电机 if(step_motorx==step_motor1) { //方向 if(dir==cw) STEP1_CW; else STEP1_CCW; HAL_TIM_OC_Start_DMA(&htim1,TIM_CHANNEL_2,(uint32_t*)step1_speed_buf,step1_speed_buf_size); //开启定时器1 CH2 STEP1_EN; } else if(step_motorx==step_motor2) { //方向 if(dir==cw) STEP2_CW; else STEP2_CCW; step_prmt[step_motorx].set_pos+=position; HAL_TIM_OC_Start_DMA(&htim1,TIM_CHANNEL_3,(uint32_t*)step2_speed_buf,step2_speed_buf_size); //开启定时器1 CH3 STEP2_EN; } else if(step_motorx==step_motor3) { //方向 if(dir==cw) STEP3_CW; else STEP3_CCW; HAL_TIM_OC_Start_DMA(&htim1,TIM_CHANNEL_4,(uint32_t*)step3_speed_buf,step3_speed_buf_size); //开启定时器1 CH4 STEP3_EN; } } } 下面是中断的处理 先是stm32f1xx_it.c文件的处理,用变量来指示哪个通道中断了。 小提示:用户自己的代码区要写到注释里有BEGIN和END的中间行,不然下次用CubeMX输出工程的时候会把用户代码覆盖。 /** * @brief This function handles DMA1 channel3 global interrupt. */ void DMA1_Channel3_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel3_IRQn 0 */ flag_DMA_CH2_TCIF=1; /* USER CODE END DMA1_Channel3_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_tim1_ch2); /* USER CODE BEGIN DMA1_Channel3_IRQn 1 */ /* USER CODE END DMA1_Channel3_IRQn 1 */ } /** * @brief This function handles DMA1 channel4 global interrupt. */ void DMA1_Channel4_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ flag_DMA_CH4_TCIF=1; /* USER CODE END DMA1_Channel4_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_tim1_ch4_trig_com); /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */ /* USER CODE END DMA1_Channel4_IRQn 1 */ } /** * @brief This function handles DMA1 channel6 global interrupt. */ void DMA1_Channel6_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */ flag_DMA_CH3_TCIF=1; /* USER CODE END DMA1_Channel6_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_tim1_ch3); /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */ /* USER CODE END DMA1_Channel6_IRQn 1 */ } 下面是回调函数处理 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { if(htim==&htim1) { if(flag_DMA_CH2_TCIF) { flag_DMA_CH2_TCIF=0; step_prmt[0].cur_pos++; //达到目标位移 if(step_prmt[0].cur_pos==step_prmt[0].set_pos) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_2); } } if(flag_DMA_CH3_TCIF) { flag_DMA_CH3_TCIF=0; step_prmt[1].cur_pos++; //达到目标位移 if(step_prmt[1].cur_pos==step_prmt[1].set_pos) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_3); } } if(flag_DMA_CH4_TCIF) { flag_DMA_CH4_TCIF=0; step_prmt[2].cur_pos++; //达到目标位移 if(step_prmt[2].cur_pos==step_prmt[2].set_pos) { HAL_TIM_OC_Stop_DMA(&htim1,TIM_CHANNEL_4); } } } } 总结 这种用法很好地解决了DMA传输数据耗内存的问题,但是缺点也有很多,这样用循环传输每次循环的内容都是一样的,不能用于步进电机加减速,而且脉冲数量控制分辨率不高,但是对于发送数量大、频率和占空比一样的脉冲是一种很好的技巧。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 02:55 , Processed in 0.909563 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号