搜索
bottom↓
回复: 2

[求助]uCOS-II下中断方式使用SPI无法运行

[复制链接]

出0入0汤圆

发表于 2017-2-17 12:06:56 | 显示全部楼层 |阅读模式
STM32F103VCT6在uCOS-II下使用SPI1,中断接收方式。现在现象是在SPI_BaudRatePrescaler 设置为SPI_BaudRatePrescaler_4时程序可以正常运行,减慢SPI总线速率则程序无法运行。异常情况下仿真程序可以运行,但运行速度明显异常。

附上SPI相关初始化及应用程序片段,望大师能帮小弟查出问题,万分感谢。

/**
******************************************************************************
* @file    BSP_LTC2315.c
* @author  
* @version V1.0
* @date    2016-12-13
* @brief   LTC2315驱动程序,完成相关GPIO初始化及SPI模块初始化。
******************************************************************************
* @attention
*
* 实验平台:3D_Ceiling_E3
* 硬件资源:
* MCU: STM32F103VCT6/LQFP100
* OSC: 8.00MHz
* 设备号 --> 短路帽 --> 引脚号(使能电平)
* CONV                 N.C                  PA04-Pin29(H)
* SCK                 N.C                  PA05-Pin30(X)-SPI1_SCK
* SDO                 N.C                  PA06-Pin31(X)-SPI1_MISO
*
******************************************************************************
**/

#include "includes.h"

extern OS_EVENT *SPI1_RXNE_sv;                        /* SPI1_RXNE 中断接收完毕信息量声明                           */
/**
******************************************************************************
* @name                SPI1_Configuration
* @param        Null
* @retval        Null
* @author        ZERO
* @version        V1.0
* @date                2015-03-11
* @brief        SPI1参数配置
******************************************************************************
**/
static void SPI1_Configuration(void)
{
        // 申请初始化结构体
        SPI_InitTypeDef  SPI_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        // Enable SPI1 and GPIO clocks
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

        // SPI_FLASH_SPI Periph clock enable
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

        // Configure SPI_FLASH_SPI pins: NSS
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        // Configure SPI_FLASH_SPI pins: SCK
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        // Configure SPI_FLASH_SPI pins: MISO
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);


        /* SPI1 configuration */

        SPI_Cmd(SPI1, DISABLE);                                                                                                // 禁用SPI1
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        // SPI模式 -> 四线制全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                                // 主机模式
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;                                        // 数据帧 -> 16Bit
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                                                        // 时钟极性 -> H
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                                                // 时钟相位 -> 偶数边采样(上升沿)
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                        // NSS由内部管脚管理
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        // FPCLK分频系数(SPI 18M@sys 72M),LTC2312_fsck_MAX:20MHz
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                        // 高位数据居前
        SPI_InitStructure.SPI_CRCPolynomial = 7;                                                        // CRC参数(多项式)
        SPI_Init(SPI1, &SPI_InitStructure);

        /* SPI1 NVIC configuration */

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

        NVIC_Init(&NVIC_InitStructure);

        SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);                                        // 开启SPI1接收中断

        ///* Enable SPI1  */
        //SPI_Cmd(SPI1, ENABLE);

}

/**
******************************************************************************
* @name                SPI_Transfer_Word
* @param        u16 tx, u16 *rx
* @retval        Null
* @author        ZERO
* @version        V1.0
* @date                2015-03-11
* @brief        SPI1读取1个word
******************************************************************************
**/

static void SPI_Transfer_Word(u16 tx, u16 *rx)
{
        INT8U err;
        union
        {
                u8 b[2];
                u16 w;
        } data_tx;                                                                        // 8Bit处理器兼容设置

        union
        {
                u8 b[2];
                u16 w;
        } data_rx;                                                                        // 8Bit处理器兼容设置

        data_tx.w = tx;

        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

        SPI1_CS_ON;                                                                        //! 1) Pull CS low
       
        #if 0                                                                                // 数据帧 -> 8Bit                       
                SPI_I2S_SendData(SPI1, data_tx.b[1]);
                OSSemPend(SPI1_RXNE_sv, 0, &err);                // 等待SPI1接收成功信号
                data_rx.b[1] = SPI_I2S_ReceiveData(SPI1);        //! 2) Read MSB and send MSB

                SPI_I2S_SendData(SPI1, data_tx.b[0]);
                OSSemPend(SPI1_RXNE_sv, 0, &err);                // 等待SPI1接收成功信号
                data_rx.b[0] = SPI_I2S_ReceiveData(SPI1);        //! 3) Read LSB and send LSB

        #else                                                                                // 数据帧 -> 16Bit
                SPI_I2S_SendData(SPI1, data_tx.w);
                OSSemPend(SPI1_RXNE_sv, 0, &err);                // 等待SPI1接收成功信号
                data_rx.w = SPI_I2S_ReceiveData(SPI1);        // 读取SPI1接收缓存器

        #endif

        *rx = data_rx.w;

        SPI1_CS_OFF;                                                                //! 4) Pull CS high
}

/**
******************************************************************************
* @name                SPI1_init
* @param        N.C.
* @retval        Null
* @author        ZERO
* @version        V1.0
* @date                2016-12-22
* @brief        SPI1初始化函数
******************************************************************************
**/

void SPI1_init(void)
{
        SPI1_Configuration();
}

/**
******************************************************************************
* @name                SPI1_connect
* @param        N.C.
* @retval        Null
* @author        ZERO
* @version        V1.0
* @date                2016-12-22
* @brief        SPI1使能函数
******************************************************************************
**/

void SPI1_connect(void)
{
        SPI1_CS_OFF;                                                        //! 1) Pull Chip Select High
        SPI_Cmd(SPI1, ENABLE);                                        //! 使能SPI
}

/**
******************************************************************************
* @name                LTC2315_read
* @param        uint16_t *adc_code
* @retval        returns 16-bit data
* @author        ZERO
* @version        V1.0
* @date                2015-03-11
* @brief        Reads the ADC  and returns 16-bit data
******************************************************************************
**/

void LTC2315_read(uint16_t *adc_code)
{
        uint16_t dummy_command = 0;

        SPI_Transfer_Word(dummy_command, adc_code);
}

/**
******************************************************************************
* @name                Data_code_to_avg
* @param        uint16_t adc_code, uint8_t shift, float vref
* @retval        缓存区平均值计算
* @author        ZERO
* @version        V1.0
* @date                2017-02-11
* @brief       
* 采样值 C、累加器 S,平均值 A,采样次数 N
* 初始化:A=初始值,S=A*N
* S = S - A + C(i)  i从第二个起,不算A
* A = S / N
* 只要 S 的量程足够,N可以任意调整。
* C = ADC读取值
* S = ADC累加器
* A = ADC平均值
* N = 样本容量
******************************************************************************
**/

uint16_t Data_code_to_avg(uint16_t C,uint16_t A,uint8_t N,uint32_t *S)
{
        *S = *S - A + C;
        return (uint16_t)(*S / N);
}

/**
******************************************************************************
* @name                LTC2315_code_to_voltage
* @param        uint16_t adc_code, uint8_t shift, float vref
* @retval        电压值转换
* @author        ZERO
* @version        V1.0
* @date                2015-03-11
* @brief        Calculates the voltage corresponding to an adc code in offset binary, given the reference voltage (in volts)
******************************************************************************
**/

float LTC2315_code_to_voltage(uint16_t adc_code, uint8_t shift, float vref)
{
        float voltage;

        adc_code = adc_code << shift;                                //!1)the data is left justified to bit_14 of a 16 bit word

        voltage = (float)adc_code;
        voltage = voltage / (pow(2, 16) - 1);                        //! 2) This calculates the input as a fraction of the reference voltage (dimensionless)
        voltage = voltage * vref;                                        //! 3) Multiply fraction by Vref to get the actual voltage at the input (in volts)

        return(voltage);
}

/**
******************************************************************************
* @name                SPI_ISR
* @param        SPI_TypeDef* SPIx
* @retval        SPI中断服务函数
* @author        ZERO
* @version        V1.0
* @date                2017-02-06
* @brief       
******************************************************************************
**/

void SPI_ISR(SPI_TypeDef* SPIx)
{
        INT8U        err = 0;

        if (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == SET)                // 接收标志位判断
        {
                SPI_I2S_ClearITPendingBit(SPIx, SPI_I2S_IT_RXNE);                        // 清除相关标志位

                if (SPIx == SPI1)
                {
                        err = OSSemPost(SPI1_RXNE_sv);                                                        // 发出SPI1信号量
                }
                                                                                               
        }
}



/*
*********************************************************************************************************
*                                   (c) Copyright 1992-2014, Shonjet
*                                           All Rights Reserved
*
* File                : app_ltc2315.c
* By                : ZERO
* Effect        : LTC2315 APP
* Version        : V1.00        09.2014
* For       : ARMv7M Cortex-M3
* System    : uCOS-II 2.86
* API                : STM32F10x_StdPeriph_Lib_V3.5.0
* Toolchain : MDK-ARM Standard Version: 4.72.0.0
* Velease Note:
* ---------------
* 1.        创建文件V1.00.                                        22.12.2016
*
* LICENSING TERMS:
* ---------------
*
*********************************************************************************************************
*/
#include "includes.h"

static uint8_t ADC_SampleSize = 30;                                                        // 设置采样样本容量                                                       

static uint8_t LTC2315_bits = 14;                                                        //!< Default set for 14 bits
static uint8_t LTC2315_shift = 1;


void Task_ADC_LTC2315(void *p_arg)
{
        uint16_t adc_code;                                                                                // The LTC2315 code
        uint16_t adc_avg;
        uint32_t adc_acc;
        float adc_voltage;                                                                                // The LTC2315 voltage


        (void)p_arg;                                                                                        /*   'p_arg' 并没有用到,防止编译器提示警告    */
                                                                                                                        /*-------------------任务主体------------------*/
        // SPI1初始化工作
        SPI1_init();
        SPI1_connect();

        LTC2315_read( &adc_code);                                                                // discard the first reading
        OSTimeDlyHMSM(0, 0, 0, 100);
        LTC2315_read( &adc_code);

        adc_code >>= 16 - LTC2315_bits;
        adc_avg = adc_code;
        adc_acc = adc_avg*ADC_SampleSize;

        while (1)
        {
                OSTimeDlyHMSM(0, 0, 0, 20);
                LTC2315_read(&adc_code);
                adc_code >>= 16 - LTC2315_bits;
                //adc_code >>= 16 - LTC2315_bits - LTC2315_shift;
                adc_avg = Data_code_to_avg(adc_code, adc_avg, ADC_SampleSize, &adc_acc);
                adc_voltage = LTC2315_code_to_voltage(adc_code, 2, 4.096);
        }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

 楼主| 发表于 2017-2-23 11:50:25 来自手机 | 显示全部楼层
求助,顶一顶

出0入0汤圆

 楼主| 发表于 2017-3-2 13:36:29 | 显示全部楼层
顶一下,求大神回复
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-28 18:59

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表