From 3a7438d9970dbfc91ba28f2feace3268c1f083ee Mon Sep 17 00:00:00 2001 From: "REASEARCHER\\18383" <1633026436@qq.com> Date: Mon, 13 Oct 2025 10:54:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E5=8F=AA=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BA=86=E9=80=9A=E8=AE=AF=E5=BA=95=E5=B1=82=E7=9A=84=E9=A9=B1?= =?UTF-8?q?=E5=8A=A8=EF=BC=8C=E5=8D=8F=E8=AE=AE=E5=B8=A7=E7=9A=84=E6=94=B6?= =?UTF-8?q?=E5=8F=91=EF=BC=8C=E5=8F=AA=E5=AF=B9=E6=B0=B4=E5=B9=B3=E7=94=B5?= =?UTF-8?q?=E6=9C=BA=E8=BF=9B=E8=A1=8C=E4=BA=86=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BSP/Driver/servoMotor/cfifo.c | 114 ++++++ BSP/Driver/servoMotor/cfifo.h | 43 ++ BSP/Driver/servoMotor/modbus_crc.c | 66 +++ BSP/Driver/servoMotor/modbus_crc.h | 7 + BSP/Driver/servoMotor/motorCommu.c | 634 +++++++++++++++++++++++++++++ BSP/Driver/servoMotor/motorCommu.h | 84 ++++ BSP/Driver/servoMotor/servoMotor.c | 71 ++++ BSP/Driver/servoMotor/servoMotor.h | 64 ++- PROJECT/OS2.ewp | 25 +- PROJECT/OS2.ewt | 21 + 10 files changed, 1124 insertions(+), 5 deletions(-) create mode 100644 BSP/Driver/servoMotor/cfifo.c create mode 100644 BSP/Driver/servoMotor/cfifo.h create mode 100644 BSP/Driver/servoMotor/modbus_crc.c create mode 100644 BSP/Driver/servoMotor/modbus_crc.h create mode 100644 BSP/Driver/servoMotor/motorCommu.c create mode 100644 BSP/Driver/servoMotor/motorCommu.h diff --git a/BSP/Driver/servoMotor/cfifo.c b/BSP/Driver/servoMotor/cfifo.c new file mode 100644 index 0000000..68e3a52 --- /dev/null +++ b/BSP/Driver/servoMotor/cfifo.c @@ -0,0 +1,114 @@ +#include "cfifo.h" + + +/*环形CFIFO初始化*/ +void CfifoBuffInit(CfifoBuff* cfifoPointer) +{ + //初始化相关信息 + cfifoPointer->Head = 0; + cfifoPointer->Tail = 0; + cfifoPointer->Lenght = 0; + memset(cfifoPointer->BUFF,'\0',CFIFO_SIZE); //环形CFIFO缓存区初始化 +} + +/*环形CFIFO数据清除*/ +void CfifoBuffClear(CfifoBuff* cfifoPointer) +{ + //清除相关信息 + cfifoPointer->Head = 0; + cfifoPointer->Tail = 0; + cfifoPointer->Lenght = 0; + memset(cfifoPointer->BUFF,'\0',CFIFO_SIZE); //环形CFIFO缓存区清除 +} + + + +/*环形CFIFO数据写入*/ +/* +*参数说明: +* Cfifo_pointer————环形CFIFO结构体 +* User_buff————待写入数据 +* num————写入数据长度 +* +*返回值说明:正确写入到FIFO缓存区中的数据长度 +* +*功能说明:将User_buff中的数据写入到环形CFIFO缓存区 +* +*/ +int16_t CfifoBuffWrite(CfifoBuff* cfifoPointer, char* userBuff, int32_t num) +{ + int16_t i , writeNum; + + if(cfifoPointer->Lenght >= CFIFO_SIZE) //判断缓存区是否已满 + { + writeNum = -1; + return writeNum; //数据溢出 + } + + if(cfifoPointer->Lenght + num < CFIFO_SIZE) //判断写入的数据长度是否超出当前可写入的最大值 + { + writeNum = num; + } + else + { + writeNum = CFIFO_SIZE - cfifoPointer->Lenght; + } + + for(i=0; iBUFF[cfifoPointer->Tail] = *(userBuff+i); + + cfifoPointer->Tail = (cfifoPointer->Tail+1) % CFIFO_SIZE;//防止越界非法访问 + } + + cfifoPointer->Lenght += writeNum; + + return writeNum; //返回正确写入的数据长度 +} + + +/*环形CFIFO读取*/ +/* +*参数说明: +* Cfifo_pointer————环形CFIFO结构体 +* User_buff————读取数据存放地 +* num————读取数据长度 +* +*返回值说明:正确读取到User_buff的数据长度 +* +*功能说明:将环形CFIFO缓存区的数据读取到User_buff +* +*/ +int16_t CfifoBuffRead(CfifoBuff* cfifoPointer, char* userBuff, int32_t num) +{ + int16_t i , readNum; + + if(cfifoPointer->Lenght == 0) //判断非空 + { + readNum = -1; + + return readNum; //没有数据 + } + + if( cfifoPointer->Lenght - num >= 0) //判断读取的数据长度是否超出当前可读取的最大值 + { + readNum = num; + } + else + { + readNum = cfifoPointer->Lenght; + } + + for(i=0; iBUFF[cfifoPointer->Head]; + + cfifoPointer->Head = (cfifoPointer->Head+1) % CFIFO_SIZE;//防止越界非法访问 + } + + cfifoPointer->Lenght -= readNum; + + return readNum; //返回正确写入的数据长度 +} + + diff --git a/BSP/Driver/servoMotor/cfifo.h b/BSP/Driver/servoMotor/cfifo.h new file mode 100644 index 0000000..2de75a0 --- /dev/null +++ b/BSP/Driver/servoMotor/cfifo.h @@ -0,0 +1,43 @@ +#ifndef _CFIFO_H_ +#define _CFIFO_H_ + +/* +************************************************************************* +* 包含的头文件 +************************************************************************* +*/ +#include +#include +#include "stdint.h" + +/* +************************************************************************* +* 变量 +************************************************************************* +*/ +#define CFIFO_SIZE 1024//环形队列CFIFO大小 + +/*环形CFIFO结构体*/ +typedef struct +{ + uint16_t Head; //环形CFIFO队列头 + uint16_t Tail; //环形CFIFO队列尾 + int32_t Lenght; //环形CFIFO数据长度 + uint8_t BUFF[CFIFO_SIZE]; //环形CFIFO缓存区 +}CfifoBuff; + + +/* +************************************************************************* +* 函数声明 +************************************************************************* +*/ +void CfifoBuffInit(CfifoBuff* cfifoPointer); //CFIFO初始化 +void CfifoBuffClear(CfifoBuff* cfifoPointer); //CFIFO数据清除 +int16_t CfifoBuffWrite(CfifoBuff* cfifoPointer, char* userBuff, int32_t num); //CFIFO数据写人 +int16_t CfifoBuffRead(CfifoBuff* cfifoPointer, char* userBuff, int32_t num); //CFIFO数据读出 + + +#endif /* _CFIFO_H_ */ + + \ No newline at end of file diff --git a/BSP/Driver/servoMotor/modbus_crc.c b/BSP/Driver/servoMotor/modbus_crc.c new file mode 100644 index 0000000..747e134 --- /dev/null +++ b/BSP/Driver/servoMotor/modbus_crc.c @@ -0,0 +1,66 @@ +#include "stdint.h" + +static const uint8_t aucCRCHi[] = { + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, + 0x00, 0xC1, 0x81, 0x40 +}; + +static const uint8_t aucCRCLo[] = { + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, + 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, + 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, + 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, + 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, + 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, + 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, + 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, + 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, + 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, + 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, + 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, + 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, + 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, + 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, + 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, + 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, + 0x41, 0x81, 0x80, 0x40 +}; + +uint16_t ModbusCRC16(uint8_t *pucFrame, uint16_t usLen) +{ + uint8_t ucCRCHi = 0xFF; + uint8_t ucCRCLo = 0xFF; + int iIndex; + + while(usLen--) + { + iIndex = ucCRCLo ^ *(pucFrame++); + ucCRCLo = (uint8_t)(ucCRCHi ^ aucCRCHi[iIndex]); + ucCRCHi = aucCRCLo[iIndex]; + } + return (uint16_t)(ucCRCHi << 8 | ucCRCLo); +} \ No newline at end of file diff --git a/BSP/Driver/servoMotor/modbus_crc.h b/BSP/Driver/servoMotor/modbus_crc.h new file mode 100644 index 0000000..173fb44 --- /dev/null +++ b/BSP/Driver/servoMotor/modbus_crc.h @@ -0,0 +1,7 @@ +#ifndef _MODBUS_CRC_H_ +#define _MODBUS_CRC_H_ + + +uint16_t ModbusCRC16(uint8_t *pucFrame, uint16_t usLen); + +#endif diff --git a/BSP/Driver/servoMotor/motorCommu.c b/BSP/Driver/servoMotor/motorCommu.c new file mode 100644 index 0000000..7ab50f7 --- /dev/null +++ b/BSP/Driver/servoMotor/motorCommu.c @@ -0,0 +1,634 @@ +#include "motorCommu.h" + + + +/* +******************************************************************************************************** +* 电机串口通讯驱动初始化相关结构体 +******************************************************************************************************** +*/ +typedef struct +{ + uint32_t gpio; //引脚端口号 + rcu_periph_enum rcuGpio; //GPIO时钟 + uint32_t uartNo; //串口号 + rcu_periph_enum rcuUart; //串口时钟 + uint32_t modePin; //rs485收发模式切换引脚 + uint32_t txPin; //串口发送引脚 + uint32_t rxPin; //串口接收引脚 + IRQn_Type uartIrq; //串口中断号 +}MotorCommuHwInfo_t;//电机与外部通讯的串口 +static MotorCommuHwInfo_t g_motorCommuBuff[] = +{ + //水平电机串口2 + { + .gpio = GPIOD, + .rcuGpio = RCU_GPIOD, + .uartNo = USART2, + .rcuUart = RCU_USART2, + .modePin = GPIO_PIN_10, + .txPin = GPIO_PIN_8, + .rxPin = GPIO_PIN_9, + .uartIrq = USART2_IRQn, + }, + //垂直电机串口5 + { + .gpio = GPIOC, + .rcuGpio = RCU_GPIOC, + .uartNo = USART5, + .rcuUart = RCU_USART5, + .modePin = GPIO_PIN_8, + .txPin = GPIO_PIN_6, + .rxPin = GPIO_PIN_7, + .uartIrq = USART5_IRQn, + }, +}; +#define MOTOR_NUM ( sizeof(g_motorCommuBuff) / sizeof(g_motorCommuBuff[0]) ) + +/* +******************************************************************************************************** +* 电机串口DMA驱动初始化结构体 +******************************************************************************************************** +*/ +typedef struct +{ + uint32_t dmaNo; //dma号,dma0或dma1 + rcu_periph_enum rcuDma; //dma时钟 + dma_channel_enum dmaTxch; //dma发送通道号 + dma_channel_enum dmaRxch; //dma接收通道号 + dma_subperipheral_enum dmaPeriph; //dma外设通道号 + uint32_t periphAddr; //dma外设地址 + IRQn_Type dmaTxIrq; //dma发送通道中断号 + IRQn_Type dmaRxIrq; //dma接收通道中断号 + uint32_t dmaTxPri; //dma发送优先级 + uint32_t dmaRxPri; //dma接收优先级 +}MotorCommuDmaHwInfo_t; + +static MotorCommuDmaHwInfo_t g_MotorDmaBuff[] = +{ + //水平电机串口2 + { + .dmaNo = DMA0, + .rcuDma = RCU_DMA0, + .dmaTxch = DMA_CH3, + .dmaRxch = DMA_CH1, + .dmaPeriph = DMA_SUBPERI4, + .periphAddr = USART2 + 0x04, + .dmaTxIrq = DMA0_Channel3_IRQn, + .dmaRxIrq = DMA0_Channel1_IRQn, + .dmaTxPri = 2,//0,1,2,3对于优先级低、中、高、特高 + .dmaRxPri = 2, + }, + //垂直电机串口5 + { + .dmaNo = DMA1, + .rcuDma = RCU_DMA1, + .dmaTxch = DMA_CH7, + .dmaRxch = DMA_CH1, + .dmaPeriph = DMA_SUBPERI5, + .periphAddr = USART5 + 0x04, + .dmaTxIrq = DMA1_Channel7_IRQn, + .dmaRxIrq = DMA1_Channel1_IRQn, + .dmaTxPri = 2,//0,1,2,3对于优先级低、中、高、特高 + .dmaRxPri = 2, + }, +}; + +/* +******************************************************************************************************** +* 电机串口通讯缓冲区初始化结构体 +******************************************************************************************************** +*/ +/* dma发送与接收缓冲区 */ +static uint8_t g_horiDmaTxBuff[DMA_BUFF_SIZE] = {0};//水平电机DMA发送缓存区 +static uint8_t g_horiDmaRxBuff[DMA_BUFF_SIZE] = {0};//水平电机DMA接受缓存区 +static uint8_t g_vertDmaTxBuff[DMA_BUFF_SIZE] = {0};//垂直电机DMA发送缓存区 +static uint8_t g_vertDmaRxBuff[DMA_BUFF_SIZE] = {0};//垂直电机DMA接受缓存区 +/* 处理串口通讯与数据缓冲的数据结构 */ +static CommuInfo_t g_horiCommuDeal; //水平电机 +static CommuInfo_t g_vertCommuDeal; //垂直电机 + +typedef struct +{ + CommuInfo_t* pCommuInfo; //串口通讯与数据缓冲相关的数据结构 + uint8_t* dmaTxBuff; //dma发送缓存区指针 + uint8_t* dmaRxBuff; //dma接受缓存区指针 +}CommuHwInfo_t;//方便缓冲区初始化的结构体 +static CommuHwInfo_t g_commuInfoBuff[] = +{ + //水平电机 + { + .pCommuInfo = &g_horiCommuDeal, + .dmaTxBuff = g_horiDmaTxBuff, + .dmaRxBuff = g_horiDmaRxBuff, + }, + //垂直电机串口5 + { + .pCommuInfo = &g_vertCommuDeal, + .dmaTxBuff = g_vertDmaTxBuff, + .dmaRxBuff = g_vertDmaRxBuff, + }, +}; + +/* +******************************************************************************************************** +* 电机串口通讯驱动初始化 +******************************************************************************************************** +*/ +static void GpioCofig(void) +{ + for(uint8_t i = 0; i < MOTOR_NUM; i++)//i==0初始化水平电机IO,i==1初始化垂直电机io + { + /*GPIO时钟初始化*/ + rcu_periph_clock_enable(g_motorCommuBuff[i].rcuGpio); + /*io复用为串口uart*/ + if ( i == H_MOTOR ) + { + gpio_af_set(g_motorCommuBuff[i].gpio, GPIO_AF_7, g_motorCommuBuff[i].txPin); + gpio_af_set(g_motorCommuBuff[i].gpio, GPIO_AF_7, g_motorCommuBuff[i].rxPin); + } + else + { + gpio_af_set(g_motorCommuBuff[i].gpio, GPIO_AF_8, g_motorCommuBuff[i].txPin); + gpio_af_set(g_motorCommuBuff[i].gpio, GPIO_AF_8, g_motorCommuBuff[i].rxPin); + } + /*tx引脚配置*/ + gpio_mode_set(g_motorCommuBuff[i].gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, g_motorCommuBuff[i].txPin); + gpio_output_options_set(g_motorCommuBuff[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, g_motorCommuBuff[i].txPin); + /*rx引脚配置*/ + gpio_mode_set(g_motorCommuBuff[i].gpio, GPIO_MODE_AF, GPIO_PUPD_NONE, g_motorCommuBuff[i].rxPin); + gpio_output_options_set(g_motorCommuBuff[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, g_motorCommuBuff[i].rxPin); + /*rs485收发模式切换引脚配置*/ + gpio_mode_set(g_motorCommuBuff[i].gpio, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, g_motorCommuBuff[i].modePin); + gpio_output_options_set(g_motorCommuBuff[i].gpio, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, g_motorCommuBuff[i].modePin); + } +} + +static void UartCofig(uint32_t baud) +{ + for(uint8_t i = 0; i < MOTOR_NUM; i++)//i==0初始化水平电机IO,i==1初始化垂直电机io + { + /*UART时钟初始化*/ + rcu_periph_clock_enable(g_motorCommuBuff[i].rcuUart); + /*串口复位*/ + usart_deinit (g_motorCommuBuff[i].uartNo); + /*串口配置*/ + usart_word_length_set(g_motorCommuBuff[i].uartNo, USART_WL_8BIT); + usart_parity_config(g_motorCommuBuff[i].uartNo, USART_PM_NONE); + usart_stop_bit_set(g_motorCommuBuff[i].uartNo, USART_STB_1BIT); + usart_baudrate_set(g_motorCommuBuff[i].uartNo, baud); + usart_hardware_flow_rts_config(g_motorCommuBuff[i].uartNo, USART_RTS_DISABLE); + usart_hardware_flow_cts_config(g_motorCommuBuff[i].uartNo, USART_CTS_DISABLE); + usart_transmit_config(g_motorCommuBuff[i].uartNo, USART_TRANSMIT_ENABLE); + usart_receive_config(g_motorCommuBuff[i].uartNo, USART_RECEIVE_ENABLE); + usart_dma_transmit_config(g_motorCommuBuff[i].uartNo, USART_DENT_ENABLE); + usart_dma_receive_config(g_motorCommuBuff[i].uartNo, USART_DENR_ENABLE); + /*中断配置*/ + usart_interrupt_enable(g_motorCommuBuff[i].uartNo, USART_INT_IDLE); + nvic_irq_enable(g_motorCommuBuff[i].uartIrq, 3, 0); + usart_enable(g_motorCommuBuff[i].uartNo); + } +} + +static void DmaCofig(void) +{ + for(uint8_t i = 0; i < MOTOR_NUM; i++)//i==0初始化水平电机IO,i==1初始化垂直电机io + { + dma_single_data_parameter_struct dmaStruct; + rcu_periph_clock_enable(g_MotorDmaBuff[i].rcuDma); + /*--------------------------------dma发送,数据完全传输中断初始化---------------------------------*/ + //dma配置 + dma_deinit(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaTxch); + dmaStruct.direction = DMA_MEMORY_TO_PERIPH; + dmaStruct.memory0_addr = (uint32_t)0; + dmaStruct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + dmaStruct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; + dmaStruct.periph_addr = g_MotorDmaBuff[i].periphAddr; + dmaStruct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + dmaStruct.number = 0; + dmaStruct.priority = CHCTL_PRIO(g_MotorDmaBuff[i].dmaTxPri); + dma_single_data_mode_init(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaTxch, &dmaStruct); + dma_circulation_disable(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaTxch); + dma_channel_subperipheral_select(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaTxch, g_MotorDmaBuff[i].dmaPeriph); + //dma中断配置 + nvic_irq_enable(g_MotorDmaBuff[i].dmaTxIrq, 4, 3); + dma_interrupt_enable(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaTxch, DMA_CHXCTL_FTFIE);//dma发送完成中断 + + + /*--------------------------------dma接收,配合串口空闲中断初始化---------------------------------*/ + //dma配置 + dma_deinit(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch); + dmaStruct.direction = DMA_PERIPH_TO_MEMORY; + dmaStruct.memory0_addr = (uint32_t)(g_commuInfoBuff[i].pCommuInfo->pDmaRsvBuff); + dmaStruct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; + dmaStruct.number = DMA_BUFF_SIZE; + dmaStruct.periph_addr = g_MotorDmaBuff[i].periphAddr; + dmaStruct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; + dmaStruct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; + dmaStruct.priority = CHCTL_PRIO(g_MotorDmaBuff[i].dmaRxPri);; + dma_memory_width_config(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch, DMA_MEMORY_WIDTH_8BIT); + dma_periph_width_config(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch, DMA_PERIPH_WIDTH_8BIT); + dma_single_data_mode_init(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch, &dmaStruct); + dma_circulation_enable(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch);//循环模式 + dma_channel_subperipheral_select(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch, g_MotorDmaBuff[i].dmaPeriph); + //中断配置 + nvic_irq_enable(g_MotorDmaBuff[i].dmaRxIrq, 4, 2); + dma_interrupt_enable(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch, DMA_CHXCTL_FTFIE); + dma_channel_enable(g_MotorDmaBuff[i].dmaNo, g_MotorDmaBuff[i].dmaRxch); + } +} + +/* +******************************************************************************************************** +* 串口缓冲区初始化 +******************************************************************************************************** +*/ +/*! + \brief 初始化串口的缓冲区指针、DMA的空间大小、DMA偏移量、发送接收队列的初始化 + \param[in] none + \param[out] none + \retval none +*/ +static void CommuStructInit() +{ + for(uint8_t i = 0; i < MOTOR_NUM; i++)//i==0初始化水平电机IO,i==1初始化垂直电机io + { + /*为属性的参数附初值*/ + CommuInfo_t *pCommuDeal = g_commuInfoBuff[i].pCommuInfo; + pCommuDeal->dmaOffset = 0; + pCommuDeal->dmaTranFlag = DMA_TRANS_IDLE; + pCommuDeal->dmaSize = DMA_BUFF_SIZE; + pCommuDeal->pDmaRsvBuff = g_commuInfoBuff[i].dmaRxBuff; + pCommuDeal->pDmaTraBuff = g_commuInfoBuff[i].dmaTxBuff; + CfifoBuffInit(&pCommuDeal->dataRsvCfifo); //用于数据接受 + CfifoBuffInit(&pCommuDeal->dataTraCfifo); //用于数据发送 + } +} + +/*! + \brief 串口进行DMA的数据发送 + \param[in] devNo:设备号,H_MOTOR:水平电机,V_MOTOR:垂直电机 + \param[in] buffer:发送缓冲区 + \param[in] len:发送缓冲区大小 + \param[out] none + \retval none +*/ +static void CommuDmaTra(uint8_t devNo, uint8_t *buffer,uint16_t len) +{ + dma_channel_disable(g_MotorDmaBuff[devNo].dmaNo, g_MotorDmaBuff[devNo].dmaTxch); + + dma_memory_address_config(g_MotorDmaBuff[devNo].dmaNo, g_MotorDmaBuff[devNo].dmaTxch, DMA_MEMORY_0, (uint32_t)buffer); + + dma_transfer_number_config(g_MotorDmaBuff[devNo].dmaNo, g_MotorDmaBuff[devNo].dmaTxch, len); + + /*清除DMA发送完成的标志*/ + dma_flag_clear(g_MotorDmaBuff[devNo].dmaNo, g_MotorDmaBuff[devNo].dmaTxch, DMA_FLAG_FTF); + usart_flag_clear(g_motorCommuBuff[devNo].uartNo, USART_FLAG_TC); + + dma_channel_enable(g_MotorDmaBuff[devNo].dmaNo, g_MotorDmaBuff[devNo].dmaTxch); +} + +/* +******************************************************************************************************** +* 水平电机相关中断服务函数 +******************************************************************************************************** +*/ +/*! + \brief this function handles DMA0_Channel3_IRQHandler interrupt + \param[in] none + \param[out] none + \retval none +*/ +void DMA0_Channel3_IRQHandler(void) +{ +/* +* 配合串口的发送。功能是继续发送缓冲区未发送的数据。 +* 发送完成配置的CNT次数后,会进入此中断函数 +*/ + int32_t TransNum = 0;//从&pCommuDeal->dataTraCfifo.BUFF[]中获取多少数据 + if(dma_interrupt_flag_get(g_MotorDmaBuff[H_MOTOR].dmaNo, g_MotorDmaBuff[H_MOTOR].dmaTxch, DMA_INT_FLAG_FTF)) + { + dma_interrupt_flag_clear(g_MotorDmaBuff[H_MOTOR].dmaNo, g_MotorDmaBuff[H_MOTOR].dmaTxch, DMA_INT_FLAG_FTF); + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[H_MOTOR].pCommuInfo; + + /*从发送循环缓冲区中获取数据*/ + TransNum = CfifoBuffRead(&pCommuDeal->dataTraCfifo,(char *)(pCommuDeal->pDmaTraBuff),pCommuDeal->dmaSize); + if(TransNum > 0) + { + CommuDmaTra(H_MOTOR, pCommuDeal->pDmaTraBuff, TransNum); + } + else + { + while(usart_flag_get(g_motorCommuBuff[H_MOTOR].uartNo, USART_FLAG_TC) == RESET); // 等待串口发送完成 + H_COMMU_RS485_RX; //485切换为接收 + pCommuDeal->dmaTranFlag = DMA_TRANS_IDLE; + } + } +} + +/** +*********************************************************** +* @brief 串口中断服务函数 +* @param +* @return +*********************************************************** +*/ +static uint16_t g_hFrameRcvNum = 0; +void USART2_IRQHandler(void) +{ + /* 串口的接收空闲中断方式进行了数据缓存。*/ + int32_t RecvNum = 0;//dma缓冲区收到多少数据 + int32_t WriteNum = 0;//向数据循环接收区写入的数据数,正常WriteNum==RecvNum + int32_t DmaIdleNum = 0;//dmasize减已经传输的数据就是DmaIdleNum + if(RESET != usart_interrupt_flag_get(g_motorCommuBuff[H_MOTOR].uartNo, USART_INT_FLAG_IDLE)) + { + /* clear IDLE flag */ + usart_interrupt_flag_clear(g_motorCommuBuff[H_MOTOR].uartNo, USART_INT_FLAG_IDLE); //第一步,读取stat0寄存器,清除IDLE标志位 + usart_data_receive(g_motorCommuBuff[H_MOTOR].uartNo); //第二步,读取数据寄存器,清除IDLE标志位 + + g_hFrameRcvNum++; + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[H_MOTOR].pCommuInfo; + + /*计算在DMA缓冲区需要获取的数据长度*/ + DmaIdleNum = dma_transfer_number_get(g_MotorDmaBuff[H_MOTOR].dmaNo, g_MotorDmaBuff[H_MOTOR].dmaRxch);//获取的是还有多少个没传输,而不是已经传输了多少 + RecvNum = pCommuDeal->dmaSize - DmaIdleNum - pCommuDeal->dmaOffset; + /*将获取到的数据放到数据接收缓冲区中*/ + WriteNum = CfifoBuffWrite(&pCommuDeal->dataRsvCfifo,(char *)(pCommuDeal->pDmaRsvBuff + pCommuDeal->dmaOffset), RecvNum); + + if(WriteNum != RecvNum) + { + printf("Uart ReadFifo is not enough\r\n"); + } + /*计算获取数据位置的偏移量*/ + pCommuDeal->dmaOffset += RecvNum; + } +} + + +void DMA0_Channel1_IRQHandler(void) +{ + int32_t RecvNum = 0; + int32_t WriteNum = 0; +/* +* 配合串口1的接收空闲中断。功能是复位DMA的偏移量 +* 1、为了串口1的空闲中断在处理数据时防止越界,将 pUartAttr->DamOffset置为0; +* 2、DMA为循环方式进行数据搬运的,当搬运完配置的Cnt后,会进入此中断处理函数, +* 3、当有数据过来时,数据将会拷贝到缓冲区的起始位置; +* 4、注意:如果DMA为正常模式,那么当完成一次拷贝后,DMA会自动disable掉。 +*/ + if(dma_interrupt_flag_get(g_MotorDmaBuff[H_MOTOR].dmaNo, g_MotorDmaBuff[H_MOTOR].dmaRxch, DMA_INT_FLAG_FTF)) + { + dma_interrupt_flag_clear(g_MotorDmaBuff[H_MOTOR].dmaNo, g_MotorDmaBuff[H_MOTOR].dmaRxch, DMA_INT_FLAG_FTF); + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[H_MOTOR].pCommuInfo; + + /* 将dma缓冲马上传输完成剩余最后一截子的数据,拷贝到缓冲区中,在进行偏移量的复位 */ + RecvNum = pCommuDeal->dmaSize - pCommuDeal->dmaOffset; + /*将获取到的数据放到数据接收缓冲区中*/ + WriteNum = CfifoBuffWrite(&pCommuDeal->dataRsvCfifo,(char *)(pCommuDeal->pDmaRsvBuff + pCommuDeal->dmaOffset), RecvNum); + if(WriteNum != RecvNum) + { + /*add deal here*/ + } + /*复位DMA偏移量*/ + pCommuDeal->dmaOffset = 0; + } +} + +/* +******************************************************************************************************** +* 垂直电机相关中断服务函数 +******************************************************************************************************** +*/ +/*! + \brief this function handles DMA0_Channel3_IRQHandler interrupt + \param[in] none + \param[out] none + \retval none +*/ +void DMA1_Channel7_IRQHandler(void) +{ +/* +* 配合串口的发送。功能是继续发送缓冲区未发送的数据。 +* 发送完成配置的CNT次数后,会进入此中断函数 +*/ + int32_t TransNum = 0;//从&pCommuDeal->dataTraCfifo.BUFF[]中获取多少数据 + if(dma_interrupt_flag_get(g_MotorDmaBuff[V_MOTOR].dmaNo, g_MotorDmaBuff[V_MOTOR].dmaTxch, DMA_INT_FLAG_FTF)) + { + dma_interrupt_flag_clear(g_MotorDmaBuff[V_MOTOR].dmaNo, g_MotorDmaBuff[V_MOTOR].dmaTxch, DMA_INT_FLAG_FTF); + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[V_MOTOR].pCommuInfo; + + /*从发送循环缓冲区中获取数据*/ + TransNum = CfifoBuffRead(&pCommuDeal->dataTraCfifo,(char *)(pCommuDeal->pDmaTraBuff),pCommuDeal->dmaSize); + if(TransNum > 0) + { + CommuDmaTra(V_MOTOR, pCommuDeal->pDmaTraBuff, TransNum); + } + else + { + while(usart_flag_get(g_motorCommuBuff[V_MOTOR].uartNo, USART_FLAG_TC) == RESET); // 等待串口发送完成 + V_COMMU_RS485_RX; //485切换为接收 + pCommuDeal->dmaTranFlag = DMA_TRANS_IDLE; + } +// pCommuDeal->dmaTranFlag = DMA_TRANS_IDLE; +// V_COMMU_RS485_RX; //485切换为接收 + } +} + +/** +*********************************************************** +* @brief 串口中断服务函数 +* @param +* @return +*********************************************************** +*/ +static uint16_t g_vFrameRcvNum = 0; +void USART5_IRQHandler(void) +{ + /* 串口的接收空闲中断方式进行了数据缓存。*/ + int32_t RecvNum = 0;//dma缓冲区收到多少数据 + int32_t WriteNum = 0;//向数据循环接收区写入的数据数,正常WriteNum==RecvNum + int32_t DmaIdleNum = 0;//dmasize减已经传输的数据就是DmaIdleNum + if(RESET != usart_interrupt_flag_get(g_motorCommuBuff[V_MOTOR].uartNo, USART_INT_FLAG_IDLE)) + { + /* clear IDLE flag */ + usart_interrupt_flag_clear(g_motorCommuBuff[V_MOTOR].uartNo, USART_INT_FLAG_IDLE); //第一步,读取stat0寄存器,清除IDLE标志位 + usart_data_receive(g_motorCommuBuff[V_MOTOR].uartNo); //第二步,读取数据寄存器,清除IDLE标志位 + + g_vFrameRcvNum++; + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[V_MOTOR].pCommuInfo; + + /*计算在DMA缓冲区需要获取的数据长度*/ + DmaIdleNum = dma_transfer_number_get(g_MotorDmaBuff[V_MOTOR].dmaNo, g_MotorDmaBuff[V_MOTOR].dmaRxch);//获取的是还有多少个没传输,而不是已经传输了多少 + RecvNum = pCommuDeal->dmaSize - DmaIdleNum - pCommuDeal->dmaOffset; + /*将获取到的数据放到数据接收缓冲区中*/ + WriteNum = CfifoBuffWrite(&pCommuDeal->dataRsvCfifo,(char *)(pCommuDeal->pDmaRsvBuff + pCommuDeal->dmaOffset), RecvNum); + + if(WriteNum != RecvNum) + { + printf("Uart ReadFifo is not enough\r\n"); + } + /*计算获取数据位置的偏移量*/ + pCommuDeal->dmaOffset += RecvNum; + } +} + + +// uint8_t rx_OK = 0; +void DMA1_Channel1_IRQHandler(void) +{ + int32_t RecvNum = 0; + int32_t WriteNum = 0; +/* +* 配合串口1的接收空闲中断。功能是复位DMA的偏移量 +* 1、为了串口1的空闲中断在处理数据时防止越界,将 pUartAttr->DamOffset置为0; +* 2、DMA为循环方式进行数据搬运的,当搬运完配置的Cnt后,会进入此中断处理函数, +* 3、当有数据过来时,数据将会拷贝到缓冲区的起始位置; +* 4、注意:如果DMA为正常模式,那么当完成一次拷贝后,DMA会自动disable掉。 +*/ + if(dma_interrupt_flag_get(g_MotorDmaBuff[V_MOTOR].dmaNo, g_MotorDmaBuff[V_MOTOR].dmaRxch, DMA_INT_FLAG_FTF)) + { + dma_interrupt_flag_clear(g_MotorDmaBuff[V_MOTOR].dmaNo, g_MotorDmaBuff[V_MOTOR].dmaRxch, DMA_INT_FLAG_FTF); + // rx_OK++; + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[V_MOTOR].pCommuInfo; + + /* 将dma缓冲马上传输完成剩余最后一截子的数据,拷贝到缓冲区中,在进行偏移量的复位 */ + RecvNum = pCommuDeal->dmaSize - pCommuDeal->dmaOffset; + /*将获取到的数据放到数据接收缓冲区中*/ + WriteNum = CfifoBuffWrite(&pCommuDeal->dataRsvCfifo,(char *)(pCommuDeal->pDmaRsvBuff + pCommuDeal->dmaOffset), RecvNum); + if(WriteNum != RecvNum) + { + /*add deal here*/ + } + /*复位DMA偏移量*/ + pCommuDeal->dmaOffset = 0; + } +} + +/* +******************************************************************************************************** +* 外部可调用API接口函数 +******************************************************************************************************** +*/ +/** +* @brief 串口设备通讯驱动初始化 +* @param +* @return +*/ +void CommuDrvInit(void) +{ + CommuStructInit();//先初始化这个缓冲区数据结构体,否则硬件配置得不到地址 + GpioCofig(); + UartCofig(57600); + DmaCofig(); +} + +/** +* @brief 通过循环队列的方式进行数据的发送 + 数据,表示已经接收到的包数量的变量减1 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @param buffer:发送缓冲区 +* @param len:发送数据的长度(不得大于DMA_BUFF_SIZE) +* @return 写入发送缓冲区的长度 +*/ +int32_t CommuTransData(uint8_t motorNo, uint8_t* buffer, int32_t len) +{ + int32_t TransNum = 0; + int32_t TransLen = 0; + // 使用数组为每个电机分配独立的计数器 + static int32_t s_addUpDataNum[MOTOR_NUM] = {0}; + + if( motorNo == H_MOTOR ) + { + H_COMMU_RS485_TX; + } + else + { + V_COMMU_RS485_TX; + } + + CommuInfo_t *pCommuDeal = g_commuInfoBuff[motorNo].pCommuInfo; + /*将要发送的数据写入循环缓冲区*/ + TransNum = CfifoBuffWrite(&pCommuDeal->dataTraCfifo, (char *) buffer, len); + s_addUpDataNum[motorNo] += len; // 使用对应电机的计数器 + + /*如果DMA未在发送中,触发发送*/ + if(pCommuDeal->dmaTranFlag == DMA_TRANS_IDLE) + { + TransLen = CfifoBuffRead(&pCommuDeal->dataTraCfifo,(char *)(pCommuDeal->pDmaTraBuff), s_addUpDataNum[motorNo]); + s_addUpDataNum[motorNo] = 0; // 清零对应电机的计数器 + if(TransLen > 0) + { + pCommuDeal->dmaTranFlag = DMA_TRANS_BUSY; + CommuDmaTra(motorNo, pCommuDeal->pDmaTraBuff, TransLen); + } + } + return TransNum; +} + +/** +* @brief 从接收循环缓冲区中读取指定长度的数据到用户数组 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @param userBuff:从接收循环缓冲区中接收数据的数组 +* @param len:接收数据的长度 +* @return none +*/ +void CommuRsvData(uint8_t motorNo, uint8_t* userBuff, uint32_t len) +{ +// if ( motorNo == H_MOTOR ) +// { +// H_COMMU_RS485_RX; +// } +// else +// { +// V_COMMU_RS485_RX; +// } + CommuInfo_t *pCommuDeal = g_commuInfoBuff[motorNo].pCommuInfo; + CfifoBuffRead(&pCommuDeal->dataRsvCfifo, (char*)userBuff, len); +} + + +/** +* @brief 与外部通讯的485或422接口,接收到的包数量 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @return rs485或rs422接收到的包数量 +*/ +uint16_t GetRsvFrameNum(uint8_t motorNo) +{ + if (motorNo == H_MOTOR) + { + return g_hFrameRcvNum; + } + + return g_vFrameRcvNum; +} +/** +* @brief 与外部通讯的485或422接口,每从缓冲区读出一包 + 数据,表示已经接收到的包数量的变量减1 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @return null +*/ +void DecRsvFrameNum(uint8_t motorNo) +{ + if (motorNo == H_MOTOR && g_hFrameRcvNum > 0) + { + g_hFrameRcvNum--; + return; + } + if (motorNo == V_MOTOR && g_vFrameRcvNum > 0) + { + g_vFrameRcvNum--; + return; + } +} + +///*用于结构体数组赋值,方便外部使用此结构体数组*/ +//CommuHwInfo_t GetMotorCommuBuffStr(uint8_t motorNo) +//{ +// return g_commuInfoBuff[motorNo]; +//} \ No newline at end of file diff --git a/BSP/Driver/servoMotor/motorCommu.h b/BSP/Driver/servoMotor/motorCommu.h new file mode 100644 index 0000000..4fd2c1a --- /dev/null +++ b/BSP/Driver/servoMotor/motorCommu.h @@ -0,0 +1,84 @@ +#ifndef _MOTORCOMMU_ +#define _MOTORCOMMU_ + +#include "gd32f4xx.h" +#include "cfifo.h" +/* +******************************************************************************************************** +* dma缓冲区相关 +******************************************************************************************************** +*/ +typedef struct +{ + int16_t dmaTranFlag; /*dma发送是否在工作的标志位*/ + int32_t dmaSize; /*DMA缓冲区的大小*/ + int32_t dmaOffset; /*获取数据在DMA缓冲区的偏移量*/ + uint8_t *pDmaRsvBuff; /*指向接收DMA缓冲区的首地址*/ + uint8_t *pDmaTraBuff; /*指向发送DMA缓冲区的首地址*/ + CfifoBuff dataRsvCfifo; /*接受数据的循环缓冲区,串口---(dma搬运)--->pDmaRsvBuff[]--->dataRsvCfifo.BUFF[]*/ + CfifoBuff dataTraCfifo; /*发送数据的循环缓冲区,dataTraCfifo.BUFF[]--->pDmaTraBuff[]---(dma搬运)--->串口*/ +}CommuInfo_t; + +#define DMA_TRANS_IDLE 0//dma当前未在发送数据 +#define DMA_TRANS_BUSY 1//dma当前正在发送数据 +#define DMA_BUFF_SIZE 256//dma缓冲区大小 +extern CommuInfo_t g_commuDeal;//来自motorCommu.c + +/* +******************************************************************************************************** +* 串口设备驱动初始化相关 +******************************************************************************************************** +*/ +#define H_MOTOR 0//数组g_motorCommuInitBuff[MOTOR_NUM]位号 +#define V_MOTOR 1 + +/*-------------485接收发送宏开关----------------------*/ +#define H_COMMU_RS485_TX gpio_bit_set(GPIOD, GPIO_PIN_10)//水平电机485发送 +#define H_COMMU_RS485_RX gpio_bit_reset(GPIOD, GPIO_PIN_10)//水平电机485接收 +#define V_COMMU_RS485_TX gpio_bit_set(GPIOC, GPIO_PIN_8)//垂直电机485发送 +#define V_COMMU_RS485_RX gpio_bit_reset(GPIOC, GPIO_PIN_8)//垂直电机485接收 + +/** +* @brief 串口设备通讯驱动初始化 +* @param +* @return +*/ +void CommuDrvInit(void); + +/** +* @brief 通过循环队列的方式进行数据的发送 + 数据,表示已经接收到的包数量的变量减1 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @param buffer:发送缓冲区 +* @param len:发送数据的长度(不得大于DMA_BUFF_SIZE) +* @return 写入发送缓冲区的长度 +*/ +int32_t CommuTransData(uint8_t motorNo, uint8_t* buffer, int32_t len); + +/** +* @brief 从接收循环缓冲区中读取指定长度的数据到用户数组 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @param userBuff:从接收循环缓冲区中接收数据的数组 +* @param len:接收数据的长度 +* @return none +*/ +void CommuRsvData(uint8_t motorNo, uint8_t* userBuff, uint32_t len); + +/** +* @brief 与外部通讯的485或422接口,接收到的包数量 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @return rs485或rs422接收到的包数量 +*/ +uint16_t GetRsvFrameNum(uint8_t motorNo); + +/** +* @brief 与外部通讯的485或422接口,每从缓冲区读出一包 + 数据,表示已经接收到的包数量的变量减1 +* @param motorNo:电机号,H_MOTOR:水平电机,V_MOTOR:垂直电机 +* @return null +*/ +void DecRsvFrameNum(uint8_t motorNo); + +///*用于结构体数组赋值,方便外部使用此结构体数组*/ +//CommuHwInfo_t GetMotorCommuBuffStr(uint8_t motorNo); +#endif \ No newline at end of file diff --git a/BSP/Driver/servoMotor/servoMotor.c b/BSP/Driver/servoMotor/servoMotor.c index 739d291..0bcd674 100644 --- a/BSP/Driver/servoMotor/servoMotor.c +++ b/BSP/Driver/servoMotor/servoMotor.c @@ -1,8 +1,79 @@ #include "servoMotor.h" +#include +/* +水平垂直电机使能开关引脚配置 +*/ +static void MotorSwitchGpioCofig(void) +{ + /*GPIO时钟初始化*/ + rcu_periph_clock_enable(RCU_GPIOE); + /*水平电机打开引脚*/ + gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0); + gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0); + /*垂直电机打开引脚*/ + gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1); + gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); + +} + +/* +从机地址 功能码 寄存器地址高 寄存器地址低 数据高位 数据低位 crc校验高位 crc校验低位 + 01H 06H 02H 00H 00H 01H 49H B2H +*/ +bool WriteMotorOneReg(uint8_t motorNo, uint16_t regAddr, uint16_t data) +{ + uint8_t frameBuff[8] = {0}; + uint8_t replyTemp[8]; + uint16_t crc; + frameBuff[0] = 0x01;//由于采用一主一从模式,所以水平电机垂直电机从机地址都是0x01,云台后期也不会扩展 + frameBuff[1] = WRITE_ONE_REG; + frameBuff[2] = regAddr >> 8; + frameBuff[3] = regAddr & 0xff; + frameBuff[4] = data >> 8; + frameBuff[5] = data & 0xff; + crc = ModbusCRC16(frameBuff, 6); + frameBuff[6] = crc & 0xff; + frameBuff[7] = crc >> 8; + + CommuTransData(motorNo, frameBuff, 8); + OSTimeDlyHMSM(0u, 0u, 0u, 5u);//发送数据完成需要2ms,接收电机返回的数据需要2ms,延时5ms足够 + + CommuRsvData(motorNo, replyTemp, 8);//数据缓冲区已经有数据了才能调用此函数提取数据进行解析 + for( uint8_t i = 0; i < 8; i++) + { + if ( frameBuff[i] != replyTemp[i] ) + { + H_MOTOR_STOP; + return false; + } + } + return true; +} +/** +* @brief 伺服电机驱动初始化 +* @param +* @return +*/ void servoMotorInit(void) { + MotorSwitchGpioCofig();//两个电机电源的开关PE0,1引脚,如果其它地方实现了,可以不需要 + H_MOTOR_OPEN; + V_MOTOR_OPEN; + + CommuDrvInit();//伺服电机RS485通讯初始化 + OSTimeDlyHMSM(0u, 0u, 0u, 500u);//等待硬件初始化成功 + WriteMotorOneReg(H_MOTOR, H02_CONTR_MODE_SELEC, 0);//H0200,选择速度模式 + WriteMotorOneReg(H_MOTOR, H04_DO1_FUNC_SELEC, 19); + + WriteMotorOneReg(H_MOTOR, H06_SPEED_COMMU_SET_VALUE, 100);//速度设置为100rpm + + WriteMotorOneReg(H_MOTOR, H06_SPEED_UP_SLOPE_VALUE, 3000);//加速度3000 + + WriteMotorOneReg(H_MOTOR, H06_SPEED_DOWN_SLOPE_VALUE, 2000);//减速度2000 + + WriteMotorOneReg(H_MOTOR, H03_DI1_LOGICAL_SELEC, 1);//只启动水平电机 } \ No newline at end of file diff --git a/BSP/Driver/servoMotor/servoMotor.h b/BSP/Driver/servoMotor/servoMotor.h index 4c9dec1..fcd0f10 100644 --- a/BSP/Driver/servoMotor/servoMotor.h +++ b/BSP/Driver/servoMotor/servoMotor.h @@ -1,8 +1,66 @@ -#ifndef _DRIVER_SERVO_MOTOR_H_ -#define _DRIVER_SERVO_MOTOR_H_ +#ifndef _SERVOMOTOR_H_ +#define _SERVOMOTOR_H_ -#include "gd32f4xx.h" +#include "motorCommu.h" +#include "modbus_crc.h" +#include "stdbool.h" +/* +******************************************************************************************************** +* 电机硬件相关 +******************************************************************************************************** +*/ +#define H_MOTOR_OPEN gpio_bit_set(GPIOE,GPIO_PIN_0) //水平电机电源打开 +#define H_MOTOR_STOP gpio_bit_reset(GPIOE,GPIO_PIN_0) //水平电机电源关闭 +#define V_MOTOR_OPEN gpio_bit_set(GPIOE,GPIO_PIN_1) //垂直电机电源打开 +#define V_MOTOR_STOP gpio_bit_reset(GPIOE,GPIO_PIN_1) //垂直电机电源关闭 +/* +******************************************************************************************************** +* 功能码命令 +******************************************************************************************************** +*/ +#define READ_ONE_REG 0X03//读单个寄存器 +#define READ_MULT_CONSE_REG 0X03//读多个连续的寄存器Read multiple consecutive registers +#define WRITE_ONE_REG 0X06//写单个寄存器 +#define WRITE_MULT_CONSE_REG 0x10//写多个连续的寄存器 + +/* +******************************************************************************************************** +* 寄存器参数 +******************************************************************************************************** +*/ +/*基本控制参数H02*/ +#define H02_CONTR_MODE_SELEC 0X0200//(Control mode selection)控制模式选择0:速度模式,1:位置模式,2:转矩模式 + +/*DI/DO参数H03~H04*/ +#define H03_DI1_FUNC_SELEC 0X0302//DI1端子功能选择,一个 DI 功能选项只能关联一个 DI 端子,不可重复分配 +#define H03_DI1_LOGICAL_SELEC 0X0303//DI1端子逻辑选择 +#define H04_DO1_FUNC_SELEC 0X0400//DO1端子功能选择 +#define H04_DO1_LOGICAL_SELEC 0X0401//DO1端子逻辑选择 + +/*速度控制参数H06*/ +#define H06_SPEED_COMMAND_SELEC 0X0602//速度指令选择 +#define H06_SPEED_COMMU_SET_VALUE 0X0603//速度指令通讯设置值,当 H06_02=0 时,通过此参数设定电机运行转速 +#define H06_SPEED_UP_SLOPE_VALUE 0X0605//速度指令加速斜坡时间常数 +#define H06_SPEED_DOWN_SLOPE_VALUE 0X0606//速度指令减速斜坡时间常数 +#define H06_SPEED_REACH_MAX 0X0618//速度到达信号阈值 + +/*RS485通讯与功能参数H0C*/ +#define H0C_COMMU_PARAM_EEPR_UPDATE 0X0C13//MODBUS通讯写入是否更新到 EEPROM,设置1为写入 + + +/* +从机地址 功能码 寄存器地址高 寄存器地址低 数据高位 数据低位 crc校验高位 crc校验低位 + 01H 06H 02H 00H 00H 01H 49H B2H +*/ +bool WriteMotorOneReg(uint8_t motorNo, uint16_t regAddr, uint16_t data); + +/** +* @brief 伺服电机驱动初始化 +* @param +* @return +*/ void servoMotorInit(void); + #endif \ No newline at end of file diff --git a/PROJECT/OS2.ewp b/PROJECT/OS2.ewp index c2b1886..d40b0a8 100644 --- a/PROJECT/OS2.ewp +++ b/PROJECT/OS2.ewp @@ -741,7 +741,7 @@ - 1 + 200 inputOutputBased @@ -826,7 +826,7 @@