^RDXX+
#include <stm32f4xx.h> xI),0db
XA^:n+Yo
#define IICRx_COUNTER 3 //I2C DMA接收数据(主机写)字节数,u16step + u8dirspd (ZR"O8
#define IICTx_COUNTER 8 //I2C DMA发送数据(主机读)字节数,u8temp + u16yrstep + u16zrstep + u16arstep + u8temp,第一个temp为了避开DMA首字节缓冲,最后一个temp为了配合CH341的多一个数据 rnr8t]
/XK`v=~(l{
u8 IIC_ADDRESS; //确定IO口后再做硬件地址 u5B/Em7,0
u:kY4T+Z
volatile u8 IIC_DMA_RxBuf[3] = {0,0,0}; y:Ab5/bHy
volatile u8 IIC_DMA_TxBuf[8] = {0,0,0,0,0,0,0,0}; xa^HU~
@+vTGjHA
/* gQt@xNO
typedef struct S;<?nz3
{ @*{BX~f
volatile u32 temp; //本次行程中步数计数器 M!i5StGC
volatile u32 step; //本次行程总步数(长行程轴步数) 0cU^ue%
volatile u32 add; //加速点 cf3c+.o
volatile u32 dect; //减速点 C)kQi2T
volatile u32 timerload; //保存计算延时值 7anpz%
volatile float timer; //计算曲线中间变量 K1WoIv<Ym
volatile u16* backtemp; //剩余步数 ;;H:$lx
}sMotor; />7/S^
!\uk b
sMotor MotorY; -+Dvyr
sMotor MotorZ; LX&P]{qKS
sMotor MotorA; JNl+UH:.
;MI<J>s
MotorY.backtemp = (u16*)(&IIC_DMA_TxBuf[1]); *0zH5c
MotorZ.backtemp = (u16*)(&IIC_DMA_TxBuf[3]); 4>#^Pk?Ra
MotorA.backtemp = (u16*)(&IIC_DMA_TxBuf[5]); <TuSU[]
8{<cqYCR
//使用原MotorP.backtemp成员变量时,改为 (* MotorY.backtemp) >Tx;<G
'Mqa2o'M
*/ {G&g+9c&
zPc;[uHT
void IIC_GET_ADDRESS() @S92D6
{ /Q_\h+`
//使能GPIO时钟 8PS:yBkA|
//配置GPIO为输入 c!T{|'?
//读IO,得到硬件IIC地址 L,/i%-J3c
IIC_ADDRESS = 0x36; // xxn&{\
?
} 'E,Yht=/}
eP?|U.on
void IIC_DMA_INIT() ijYLf.R<
{ Z`KmH.l!
IIC_GET_ADDRESS(); N|LVLsK
UQ~rVUo.c
RCC->AHB1ENR |= RCC_AHB1RSTR_DMA1RST; //使能DMA1时钟 t}gqk'
A'EA !
//IIC DMA 从机接收 (主机写) c.WT5|:qw
DMA1_Stream0->CR &= ~DMA_SxCR_EN; //除能DMA1_Stream0 {`Z)'G\`
while(DMA1_Stream0->CR & DMA_SxCR_EN);//确保DMA可以被设置 6iWuBsal
DMA1->LIFCR |= (DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0 | DMA_LIFCR_CFEIF0);//传送前清空DMA1_Stream0所有中断标志 $)~]4n=
DMA1_Stream0->PAR = (uint32_t)&I2C1->DR ;//设置外设地址I2C1->DR地址 9@B+$~:}7
DMA1_Stream0->M0AR = (uint32_t)IIC_DMA_RxBuf; //设置内存地址 i=+6R
DMA1_Stream0->NDTR = IICRx_COUNTER; //设置dma传输数据的数量 N!,l4!M\N
DMA1_Stream0->CR |= (DMA_SxCR_CHSEL_0 | DMA_SxCR_PL_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC); //设置通道号1,优先级中级,传输方向外设到内存(0不用设),内存递增 ]0le=Ee^%
DMA1_Stream0->CR |= DMA_SxCR_EN; //开启DMA 9=f'sqIPV
swA"_A8>u
//IIC DMA 从机发送 (主机读) .Ps;O
DMA1_Stream6->CR &= ~DMA_SxCR_EN; //除能DMA1_Stream6 CcTJCuOS
while(DMA1_Stream6->CR & DMA_SxCR_EN);//确保DMA可以被设置 |O?Aj1g[c?
DMA1->HIFCR |= (DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5);;//传送前清空DMA1_Stream6所有中断标志 9g"H9)EZ^
DMA1_Stream6->PAR = (uint32_t)&I2C1->DR ;//设置外设地址I2C1->DR地址 |93%,
DMA1_Stream6->M0AR = (uint32_t)IIC_DMA_TxBuf; //设置内存地址 48`<{|r{
DMA1_Stream6->NDTR = IICTx_COUNTER; //设置dma传输数据的数量 $@j7VPE
DMA1_Stream6->CR |= ( DMA_SxCR_CHSEL_0 | DMA_SxCR_PL_0 | DMA_SxCR_DIR_0 | DMA_SxCR_MINC | DMA_SxCR_CIRC);//设置通道号1,优先级中级,传输方向内存到外设,内存递增 3R><AFMY?
DMA1_Stream6->CR |= DMA_SxCR_EN; !c7Od
)]
\m!."~%
~^*tIIOX
RCC->AHB1ENR |= RCC_AHB1RSTR_GPIOBRST; //使能GPIOB时钟 AtOB'=ph*
|&Q=9H*e
GPIOB->AFR[0] &= ~0xFF000000; //设置PB6 7复用IIC模式 =$Z'F<|d
GPIOB->AFR[0] |= 0x44000000; //设置PB6 7复用IIC模式 }2@$2YR[
GPIOB->MODER &= ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7); //设置PB6、7为复用模式 HPQ ,tlp6j
GPIOB->MODER |= (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1); s@|?N+z
GPIOB->OTYPER |= (GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7);//设置PB6、7为开漏输出 zU%aobZ
GPIOB->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7); //设置PB6、7速度50M \=<.0K A~
GPIOB->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR6_1 | GPIO_OSPEEDER_OSPEEDR7_1); //设置PB6、7速度50M :xV&%Qa1
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR6 | GPIO_PUPDR_PUPDR7); //设置PB6 7 上拉 /MC\!,K
GPIOB->PUPDR |= (GPIO_PUPDR_PUPDR6_0 | GPIO_PUPDR_PUPDR7_0); //设置PB6 7 上拉 eC-TZH@
"e"`Or
^ytd~iK8
RCC->APB1ENR |= RCC_APB1RSTR_I2C1RST; //开启IIC1时钟 N_0O"" d
r.GjM#X
I2C1->CR1 |= (I2C_CR1_PE | I2C_CR1_ACK); //启用IIC2模块,并设置应答位 #C`!yU6(
I2C1->CR1 &= ~I2C_CR1_SMBUS; //设置为IIC模式 Yq_zlxd%F
I2C1->OAR1 &= ~I2C_OAR1_ADDMODE; //设置为7位地址模式 4\?B,!
I2C1->OAR1 |= 0x4000; //手册上说改为需要由软件置1 h(sD] N
I2C1->OAR1 |= IIC_ADDRESS; //设置地址 pqK3u)
//I2C1->OAR2 = (IIC_ADDRESS_2 | 0x01); //设置地址并启用双地址 *)1,W+A5L
I2C1->CR2 |= (I2C_CR2_DMAEN); @b
zrJ7$
I2C1->CR1 |= I2C_CR1_NOSTRETCH; A@]
n"
} Q7\Ax0
3kMiC$
N?XN$hwdZ
|]Xw1.S.L