中级会员
 
- 积分
- 211
- 金钱
- 211
- 注册时间
- 2017-6-16
- 在线时间
- 46 小时
|
5金钱
SPI通信,STM32作为主机,GP21作为从机;主机取出的数据总是为65536.000000.先把GP21相关SPI贴出再贴代码。求助坛友们。
以下为相关代码
配置SPI:(STM32为主机,GP21为从机,CPOL=0,CPHA=1.NSS由C7管脚控制)
void SPI2_Configuration(void) //SPI2 与TDC-GP21通信
{
SPI_InitTypeDef SPI_InitStructure;//声明一个结构体变量
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主spi
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//数据大小:8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CP0L=0 CLK的初始状态 时钟不是片选
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //采样延迟 第2个时钟采样 CPHA=1
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制 C7控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //波特率预分频值为36MHZ/256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传送从最高位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2,&SPI_InitStructure);
SPI_Cmd(SPI2,ENABLE);//使能SPI2
}
SPI读写函数:
u8 SPI2_WriteReadData(u8 dat) //SPI读写函数 片选放在里面一次性操作 别的函数里不用单独操控了
{
u8 readdata;
u16 i = 0;
/* 当发送缓冲器空 */
GPIO_ResetBits(GPIOC, GPIO_Pin_7); delay(5);//打开片选
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //如果得到的发送缓冲器为0 表示不空 则不发送数据只是进行i++等待发送缓冲器为1 为1 while不成立跳出循环执行发送语句
{
i++;
if(i > 10000)
{printf("发送失败");return 0x01;}
}
/* 发送数据*/
SPI_I2S_SendData(SPI2, dat);
/* 等待接收缓冲器为非空 */
i=0;
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
i++;
if(i > 10000)
{printf("接收失败");return 0x01;}
}
//返回1则为非空while不成立跳出while将非空的数据读出来 如果空了则返回0 while成立进行循环不读数
/* 将读取到的数值返回 */
readdata=SPI_I2S_ReceiveData(SPI2);
GPIO_SetBits(GPIOC, GPIO_Pin_7);delay(10); //关闭片选
return readdata;
}
SPI写32位数和读32位数:(写是配置GP21相关功能,读是读取GP21测量数据)
void SPI_WRITE_DATA32(u32 data) //写32位数对GP21进行配置 前8位地址后24位配置
{
SPI2_WriteReadData((u8)((data) >> 24)); //32位右移24位是将高8位移到低8位上并截断 然后按照从高位到低位发送
SPI2_WriteReadData((u8)((data) >> 16));//连续发送32位数据对GP21进行配置
SPI2_WriteReadData((u8)((data) >> 8));
SPI2_WriteReadData((u8)data);
}
float SPI_READ32_DATA(u8 ml) //读32位数据 GP21测量数据格式为32位,其中前16位为整数后16位为小数
{
u16 data1=0x0000,data2=0x0000;
float data3=0;
SPI2_WriteReadData(ml);
data1|= SPI2_WriteReadData(0xFF)<<8; //先移位再位或
data1|= SPI2_WriteReadData(0xFF);
data2|= SPI2_WriteReadData(0xFF)<<8;
data2|= SPI2_WriteReadData(0xFF);
data3=(float)data1+(float)data2/65536;
return data3;
}
GPIO配置:(B13 14 15为SPI2管脚。C7控制片选SSN)
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; //SPI2管脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用功能输出 B14与外设连接 由外设决定
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6; //C7控制TDC-GP21的SPI片选CS C6控制led点灯
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
串口中断函数:(当作一个开关触发测量。shice初始为0主函数中if不成立,串口改变shice为1使if成立)
void USART1_IRQHandler(void)
{
int ReceiveDate=1; //定义一个变量存放数据
GPIO_ResetBits(GPIOC, GPIO_Pin_6);
delay(10000);
if(!(USART_GetITStatus(USART1,USART_IT_RXNE))); //读取接收中断标志位USART_IT_RXNE
//USART_FLAG_RXNE:接收数据寄存器非空标志位
//1:忙状态 0:空闲(没收到数据,等待。。。)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志
SPI2_WriteReadData(0xB5); //0xB5为读GP21寄存器REG_1高8位,用来测试SPI通信
ReceiveDate=SPI2_WriteReadData(0xFF);
shice=0;GPIO_SetBits(GPIOC, GPIO_Pin_7);// 这时shice还不能为别的数 因为还没有配置完成
GPIO_init();GP2_init();delay(10); //GPIO中执行电平复位并拉高SPI片选CS端 GP2中执行相关寄存器配置
kflag=0;cs=10;delay(5); //设置一次测量多少数据
pj=0;memset(c1,0,sizeof(c1));c2=0;cnt1=0;cnt2=0; delay(1); //对相关统计数进行清0
shice=1;t0=1; //打开shice使主函数中的if成立
printf("\nREG_1-8=%d\n",ReceiveDate); printf("cnt=%d\n",cs);
GPIO_SetBits(GPIOC, GPIO_Pin_6);
}
}
主函数:
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
TIM2_Configuration();
USART_Configuration();
SPI2_Configuration();
NVIC_Configuration();
GPIO_SetBits(GPIOC, GPIO_Pin_7); //SPI片选管脚先为1 不打开CS
GPIO_init(); //电源reset
GP2_init(); //配置GP21相关 设置测量范围 通道 晶振 校准等
SPI2_WriteReadData(0x70);delay(1); //0x70给GP21初始化
GPIO_SetBits(GPIOC, GPIO_Pin_0|GPIO_Pin_1); //使能start和stop1管脚
GPIO_SetBits(GPIOC, GPIO_Pin_7); //SPI片选管脚先为1 不打开CS
while(1) // 串口执行完后kflag=0,cs=10 ;shice=1;t0=1; if成立开始打印测量数据
{
if((shice!=0)&&(t0==1 )) //t0初始为1 shice初始为0 不成立 在串口里修改为1后才成立
{
SPI2_WriteReadData(0x70);delay(1); // 初始化
ret=shishicl();//时间测量 float型浮点数 调用之后SSN=1 kflag在累加 每用完一次后t0都被置1使if一直成立
if(kflag==cs) //cs是设置的测量次数 kflag在shishicl函数里累加 一直加到cs停止
{ t0=0;kflag=0;
pj=pj/cnt1;p=cnt1;printf("pj=%f\n cnt1=%d\n",pj,cnt1); //数据处理
while(p--)
{ if((c1[p]>(pj-0.0035))&&(c1[p]<(pj+0.0035)))
{c2+=c1[p];cnt2++;}
}
printf("pj=%f\n cnt2=%d\n",c2/cnt2,cnt2);
}
pj+=ret;c1[cnt1]=ret;cnt1+=1;
printf("%f\n",ret);
}
}
}
测试结果:(串口打印)
REG_1-8=255
cnt=10
65536.000000
65536.000000
65536.000000
65536.000000
65536.000000
65536.000000
65536.000000
65536.000000
65536.000000
pj=65536.000000
cnt1=9
pj=65536.000000
cnt2=9
65536.000000
修改了好几次都是这个数,尝试把MOSI和MISO对调结果变为全0.
我自己感觉问题可能是出在写和读32位数函数那里有问题;GP21大多要读写32位,而STM32为8位,读写32位是参考了开发板历程的程序。
我之前用的51单片机进行SPI通信完全没问题,测试结果良好;感觉STM32的SPI有点复杂,而且帧格式只支持8或16位。
希望路过的朋友指点迷津。
|
最佳答案
查看完整内容[请看2#楼]
反复调试,问题已解决。
发现读32位数据和写32位数据,不能向上面函数这样写。
发送时需要把32位截断成4个8位分开4次发送
接收的时候也是分4次接收各8位之后在拼接
|