直接上代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : adc_dma.c
* @brief : adc_dma program body
******************************************************************************
* @attention
* F7 开启L1-cache会导致DMA数据不更新。例如串口,adc
* https://bbs.21ic.com/icview-2380632-1-1.html
* 如果程序默认内存地址设置为0x20020000开始,即运行于SRAM1,才会出现这种现象。
* 如果默认内存地址为0x20000000开始,即运行于DTCM,结果是正常的,开启D-cache正常。
* DMA如果使用了SRAM1,要么就不使用D-cache,要使用D-cache就要手动clean,或者设置为write-through
* 另一种解决办法如本代码所示,
* https://blog.csdn.net/weifengdq/article/details/121802176
* @author HLY
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "adc_dma.h"
/* Private includes ----------------------------------------------------------*/
#include "adc.h"
/* Private define ------------------------------------------------------------*/
#define ADC1_BUFFER_SIZE 32*1 //ADC1用了4通道, 存32组, 方便做平均
//#define ADC3_BUFFER_SIZE 32*8 //ADC3用了8通道, 存32组, 方便做平均
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/*
@Note If the application is using the DTCM/ITCM memories (@0x20000000/ 0x0000000: not cacheable and only accessible
by the Cortex M7 and the MDMA), no need for cache maintenance when the Cortex M7 and the MDMA access these RAMs.
If the application needs to use DMA(or other masters) based access or requires more RAM, then the user has to:
- Use a non TCM SRAM. (example : D1 AXI-SRAM @ 0x24000000)
- Add a cache maintenance mechanism to ensure the cache coherence between CPU and other masters(DMAs,DMA2D,LTDC,MDMA).
- The addresses and the size of cacheable buffers (shared between CPU and other masters)
must be properly defined to be aligned to L1-CACHE line size (32 bytes).
*/
//32字节对齐(地址+大小)
//adc1_data指定到 AXI SRAM 的0x20020000 //设置不正确会进不了debug
//adc3_data指定到 SRAM4 的0x38000000 //
ALIGN_32BYTES (uint16_t adc1_data[ADC1_BUFFER_SIZE]) __attribute__((section(".ARM.__at_0x20020000")));
//ALIGN_32BYTES (uint16_t adc3_data[ADC3_BUFFER_SIZE]) __attribute__((section(".ARM.__at_0x38000000")));
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/**
* @brief adc_dma初始化
* @param None
* @retval None
* @note 函数放在初始化阶段
*/
void adc_dma_init()
{
if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_data, ADC1_BUFFER_SIZE) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief 返回adc值
* @param None
* @retval None
* @note None
*/
float get_adc_value()
{
uint32_t ADC_Value = 0;
for(int i = 0; i < ADC1_BUFFER_SIZE; ++i)
ADC_Value += adc1_data[i];
ADC_Value = ADC_Value / ADC1_BUFFER_SIZE;
return ADC_Value * 3.3 / 4096;
}
/**
* @brief ADC_DMA 半满回调函数
* @param None
* @retval None
* @note ADC转换半满中断中把数据存到数组的前半部分
ping-pong存储
FIFO
*/
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer */
if(hadc->Instance == ADC1) {
SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_data[0], ADC1_BUFFER_SIZE);
}
}
/**
* @brief ADC_DMA 转换完成回调函数
* @param None
* @retval None
* @note ADC转换完成中断中把数据存到数组的后半部分
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Invalidate Data Cache to get the updated content of the SRAM on the second half of the ADC converted data buffer */
if(hadc->Instance == ADC1)
{
SCB_InvalidateDCache_by_Addr((uint32_t *) &adc1_data[ADC1_BUFFER_SIZE/2], ADC1_BUFFER_SIZE);
}
}
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
cube生成debug模式使用JINK(5PIN),不然容易KIEL闪退。
独立看门狗 4s一次。超过4s没更新 即复位
nvic优先级设置
中断 抢占优先级 子优先级
系统时钟 0 0
TIM4(FREEMODBUS时钟)0 1[不可改变,已测试]
串口1 0 2[不可改变,已测试]
TIM1捕获(PWM) 2 2
TIM3(编码器) 3 1
外部中断1和2 3 2
TIM1更新中断(没用) 3 3
GPIO
TIM2_CH2 PA1
MOTOR_TURN PA2
ADC1_IN5 PA5
TIM3_CH1 PA6
TIM3_CH2 PA7
USART1_TX PA9
USART1_RX PA10
Photoelectric_Sensor1 PB0
LED PB1
Photoelectric_Sensor2 PC4
RCC_OSC_IN PH0
RCC_OSC_OUT PH1
USART1:用于MODBUS传输
TIM1:用于计数脉冲个数。 https://www.jianshu.com/p/eae5386aa8ee
TIM2:输出PWM https://www.jianshu.com/p/eae5386aa8ee
TIM3:正交解码模式。 https://blog.csdn.net/csol1607408930/article/details/112793292
tim4:用于连接porttimer.c文件的函数,启用FREEMODBUS https://blog.csdn.net/ASWaterbenben/article/details/105549750
* @author HLY
******************************************************************************
**/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* CUBE Includes */
#include "gpio.h"
#include "dma.h"
/* FREEMODBUS Includes */
#include "mb.h"
#include "port.h"
#include "demo.h"
/* C Includes */
#include "stdio.h"
/* user Includes */
#include "motor.h"
#include "encoder.h"
#include "led.h"
#include "adc_dma.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
u8 once_flag = 1;//仅运行一次标志位。只有当其为0,才运行其他代码
uint8_t zero_error = HAL_BUSY;//零位传感器错误码
float ane = -90,adc = -1;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* 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 */
MX_GPIO_Init();
MX_DMA_Init(); //DMA必需放在要使用设备前面!!!
MX_TIM1_Init(); //TIM1必需在TIM2前面初始化!!!
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_TIM4_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_TIM2_Init();
MX_IWDG_Init();
/* USER CODE BEGIN 2 */
eMBInit( MB_RTU, 0x01, 1, 9600, MB_PAR_NONE); //初始化modbus,走modbusRTU,从站地址为0x01,端口为1。
eMBEnable( ); //使能modbus
use_led_init(); //LED初始化
adc_dma_init(); //adc_dma初始化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_IWDG_Refresh(&hiwdg); //看门狗喂狗[debug设置断点时请注释看门狗]
modbus_handler(); //modbus处理函数
(void)eMBPoll(); //启动modbus
//adc = get_adc_value();
if(!once_flag)
{
motor_Absolute_angle_out(ane);
}
else if(once_flag)
{
if(Zero_Detection(0X2FFFFF) == HAL_OK)
{
HAL_Delay(500);
once_flag = 0;
pusle_it = 0;//初始化电机脉冲计数值
motor_out_ok = HAL_OK;
}
else if(zero_error == HAL_TIMEOUT)
{
use_led_setmode();//如果归零传感器异常超时,led灯两闪两灭
while(1);//错误
}
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 432;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Activate the Over-Drive mode
*/
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */