本帖最后由 he07413 于 2016-8-10 15:55 编辑
1.SPI总线读取传感器数据,普通查询方式效率太低,所以不用。2.这里使用中断方式,中断里只做数据接收、切换片选。尽可能让中断程序简短。
3.每当中断服务程序一次读取一轮挂在同一总线的所有传感器时,发送事件通知任务处理数据。
4.为了保证采样率,又不至于频繁中断,APB1进行256分频,SPI时钟频率仍可达到195.312K。每秒传输24414个字节,这次使用的霍尼韦尔传感器4个字节得到一个数据。总线上挂2个传感器,对每个传感器而言,每秒达到3051的采样率。
5.这样两个传感器依次读取(8字节),用时320us,为了减少任务调度,和保证数据处理时间,读取四轮发送一次事件通知数据处理任务处理。
程序按照以上思路来写,首先初始化SPI
- void SPI2_init(void)
- {
- static uint8_t SPI2_FlagStatus = 0;
- if(SPI2_FlagStatus)
- return;
- SPI2_FlagStatus = 1;
-
- SPI_InitTypeDef SPI_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
-
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_SPI2);
- GPIO_PinAFConfig(GPIOC,GPIO_PinSource2,GPIO_AF_SPI2);
- GPIO_PinAFConfig(GPIOC,GPIO_PinSource3,GPIO_AF_SPI2);
-
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
- GPIO_Init(GPIOB,&GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
-
- SPI_Cmd(SPI2, DISABLE);
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Ë«ÏßÈ«Ë«¹¤
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Ö÷ģʽ
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //Êý¾Ý´óС8λ
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //ʱÖÓ¼«ÐÔ£¬¿ÕÏÐʱΪµÍ
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //µÚ1¸ö±ßÑØÓÐЧ£¬ÑØΪ²ÉÑùʱ¿Ì //
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSSÐźÅÓÉÈí¼þ²úÉú
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //·ÖƵ 50M/256 = 195.312K
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //¸ßλÔÚÇ°
- SPI_InitStructure.SPI_CRCPolynomial = 7; //CRCÖµ¼ÆËãµÄ¶àÏîʽ
- SPI_Init(SPI2,&SPI_InitStructure);
-
- NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- // SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
- // SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_ERR, ENABLE);
- SPI_Cmd(SPI2,ENABLE);
- }
复制代码
时钟是100M,APB1设置的2分频。SPI时钟由APB1 256分频得到
以下是中断服务程序,系统启动之后,由任务打开SPI接收中断,通过随便向SPI总线发送一个数据来触发接收。中断服务程序只接收数据。
- void SPI2_IRQHandler(void)
- {
- static int16_t i = -1;
- if(i<0) //丢弃第一次开机读回的数据
- {
- SPI_I2S_ReceiveData(SPI2);
- i = 0;
- }
-
- if(SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET)
- SPI2DataBuf[8*SPICircle-(++i)] = SPI_I2S_ReceiveData(SPI2);
-
- if((8*SPICircle)==i)
- {
- osSignalSet(HSCMTskId,SPI2RecvOverFlag);
- i = 0;
- }
-
- switch(i%4!=0?i+1:i/4%2)
- {
- case 0:
- HSCMChipaEnable();
- SPI_I2S_SendData(SPI2, 0x55);break;
- case 1:
- HSCMChipbEnable();
- SPI_I2S_SendData(SPI2, 0x46);break;
- default:
- SPI_I2S_SendData(SPI2, 0);
- }
- }
复制代码
任务函数里时钟等待接收完成事件,第一时间把SPI数据缓存区里的数据复制出来,进行数据处理。主要包括求平均、滤波 等
- void HSCMTsk(void const *arg)
- {
- SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
- SPI_I2S_SendData(SPI2, 0);
- for(;;)
- {
- osSignalWait(SPI2RecvOverFlag,osWaitForever); //
- HSCM_GetData(); //SPI2ÉÏ2¸ö´«¸ÐÆ÷¶ÁÊý´¦Àí
- osSignalClear(HSCMTskId,SPI2RecvOverFlag);
- osDelay(1);
- }
- }
- void HSCM_GetData(void)
- {
- uint8_t i = 0,j = 0;
- for(;i<8*SPICircle;i+=4)
- {
- if(0==((i/4)%2))
- j = 0;
- if((0==(SPI2DataBuf[i+3]&0xC0))&&SPI2DataBuf[i+3]) //״̬ΪΪ00£¬Êý¾Ý¸ñʽ00xx xxxx
- {
- switch((i/4)%2) //ÓÐЧÊý¾Ý¼ÆÊý
- {
- case 0:HSCMChipaNum++;break;
- case 1:HSCMChipbNum++;break;
- default:;
- }
- SPI2SensorData[j] += *(uint16_t*)&SPI2DataBuf[i];
- SPI2SensorData[j+1] += *(uint16_t*)&SPI2DataBuf[i+2];
- }
- j += 2;
- }
-
- if(AvrgNum==++SPI2DataNum) //30*SPICircrle¸öÊý¾Ýµã
- {
- SPI2DataNum = 0;
- if(HSCMChipaNum)
- {
- SPI2SensorData[0] /= HSCMChipaNum;
- SPI2SensorData[1] /= HSCMChipaNum;
- HSCMChipaNum = 0;
- }
- if(HSCMChipbNum)
- {
- SPI2SensorData[2] /= HSCMChipbNum;
- SPI2SensorData[3] /= HSCMChipbNum;
- HSCMChipbNum = 0;
- }
- }
- // GPIO_PIN_TogglePin(GPIOA,GPIO_Pin_5);////²âÊÔSPI²É¼¯Ò»ÂÖÊý¾ÝµÄʱ¼ä£¬Ê±ÖÓƵÂÊ195.312K
- }
复制代码
硬件的连线图如图,之所以没接传感器,一是这个板子不方便接两个霍尼韦尔传感器,二是,一旦我们发送的数据是正确的,时序又没问题,传感器回复肯定正常,除非是传感器的问题。所以只需要看后面的测试波形就可以确定我们程序是否正确。
实际SPI总线上的波形如下:
从上到下的线序依次为:
1.SPI时钟
2.SPI主出从入
3.SPI主入从出
4.传感器1的片选
5.传感器2的片选
6.传感器1的协议数据解析
7.传感器2的协议数据解析
可以看出SPI总线按照我们预想的方式在工作。时钟线拉低之后发送的第一个字节对一般传感器来说是个指令,后面紧跟着3个字节的数据为传感器返回给我们的值。这里 故意在第一个字节发送 0x55 0x46 只是为了方便观察。
如果感兴趣,可以下载附件里的工程查看详细内容。也可以跟我讨论。
|