使用STM32的两个硬件SPI完成数据的读写,具体的见程序注释

  1 /**************************(C) COPYRIGHT SunHao 2011***************************
  2 名称:ADDA.c
  3 功能:ADDA的相关配置以及读取函数
  4 作者:孙浩
  5 时间:2011.4.25
  6 版本:1.0
  7 注意:对照TLC2543时序图,确保对应时序一致,读写速度不宜太快
  8 *******************************************************************************/
  9 #include "STM32Lib//stm32f10x.h"
 10 #include "hal.h"
 11 //模拟开关CD4051对应的通道选择IO定义
 12 #define A_OFF    GPIO_ResetBits(GPIOF, GPIO_Pin_8)
 13 #define A_ON     GPIO_SetBits(GPIOF, GPIO_Pin_8)
 14 #define B_OFF    GPIO_ResetBits(GPIOF, GPIO_Pin_7)
 15 #define B_ON     GPIO_SetBits(GPIOF, GPIO_Pin_7)
 16 #define C_OFF    GPIO_ResetBits(GPIOF, GPIO_Pin_6)
 17 #define C_ON     GPIO_SetBits(GPIOF, GPIO_Pin_6)
 18 /*******************************************************************************
 19 名称:void ADDA_Config(void)
 20 功能:配置ADDA对应的SPI和IO
 21 参数:无
 22 时间:2011.4.20
 23 版本:1.0
 24 注意:配置类似函数一定要注意外设时钟使能,所有用到引脚时钟使能
 25 *******************************************************************************/
 26 void ADDA_Config(void)
 27 {
 28     SPI_InitTypeDef  SPI_InitStructure;
 29     GPIO_InitTypeDef GPIO_InitStructure;
 30     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
 31     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
 32     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOF,ENABLE);
 33     /*TLC2543相关IO口定义  */
 34     /* PA5-SCK PA7-MOSI */
 35     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5 |GPIO_Pin_7 ;
 36     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 37     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 38     GPIO_Init(GPIOA, &GPIO_InitStructure);
 39     /*PA4-CS*/
 40     GPIO_SetBits(GPIOA, GPIO_Pin_4);
 41     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
 42     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 43     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 44     GPIO_Init(GPIOA, &GPIO_InitStructure);    
 45 
 46     /*PA6-MISO*/
 47     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
 48     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 49     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
 50     GPIO_Init(GPIOA, &GPIO_InitStructure);
 51     
 52     /*TLV5614相关IO口定义  */
 53     /* PB13-SCK PB15-MOSI */
 54     GPIO_InitStructure.GPIO_Pin =GPIO_Pin_13 |GPIO_Pin_15 ;
 55     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 56     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 57     GPIO_Init(GPIOB, &GPIO_InitStructure);
 58     /*PB12-CS PB11-FS*/
 59     GPIO_SetBits(GPIOB, GPIO_Pin_11);//帧同步信号和片选信号初始化为高电平
 60     GPIO_ResetBits(GPIOB, GPIO_Pin_12);
 61     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
 62     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 63     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 64     GPIO_Init(GPIOB, &GPIO_InitStructure);    
 65 
 66     /* SPI1 configuration 具体的SPI时序严格参照TLC2543数据手册*/
 67     SPI_Cmd(SPI1, DISABLE);                                                 //必须先禁能,才能改变MODE
 68     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        //两线全双工
 69     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                            //
 70     SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;                        //16位
 71     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                //时钟脚空闲时保持低电平
 72     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                            //在第一个时钟沿采样数据信号
 73     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                //软件NSS,片选信号由软件产生
 74     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;    //256分频
 75     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                        //高位在前
 76     
 77     SPI_Init(SPI1, &SPI_InitStructure);
 78     SPI_Cmd(SPI1, ENABLE); 
 79     /* SPI2 configuration 具体的SPI时序严格参照TLV5614数据手册*/
 80     SPI_Cmd(SPI2, DISABLE);                                                 //必须先禁能,才能改变MODE
 81     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        
 82     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                            //
 83     SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;                        //16位
 84     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                //时钟脚空闲时保持低电平
 85     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                            //在第一个时钟沿采样数据信号
 86     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                //软件NSS,片选信号由软件产生
 87     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;    //256分频
 88     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                        //高位在前
 89     
 90     SPI_Init(SPI2, &SPI_InitStructure);
 91     SPI_Cmd(SPI2, ENABLE); 
 92     //模拟开关通道选择IO口定义    
 93     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
 94     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //开漏输出
 95     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //50M时钟速度
 96     GPIO_Init(GPIOF, &GPIO_InitStructure);
 97     A_OFF;
 98     B_OFF;
 99     C_OFF;
100     GPIO_SetBits(GPIOB, GPIO_Pin_11);//帧同步信号初始化为高电平
101     GPIO_ResetBits(GPIOB, GPIO_Pin_12);
102 }
103 /*******************************************************************************
104 名称:u16 Read_AD(u16 chan)
105 功能:读取对应通道的AD值
106 参数:chan对应的通道,取值0-15,返回值0-4095
107 时间:2011.4.20
108 版本:1.0
109 注意:后八个通道是通过模拟开关切换,受模拟开关切换速度影响,能够读取的速度要比
110       前八个通道慢
111 *******************************************************************************/
112 u16 Read_AD(u16 chan)
113 {
114     u16 i,ADCdata,chanaddr;
115     if(chan<=7)
116     {
117         chanaddr= chan <<12;
118         chanaddr|=0x0C00; 
119     }
120     else
121     {
122         chanaddr=8;//通过模拟开关进行输入,模拟开关接入第八通道
123         chanaddr<<=12;
124         chanaddr|=0x0C00; 
125         switch (chan)
126         {
127             case 8:
128                 A_OFF;
129                 B_OFF;
130                 C_OFF;
131                 break;
132             case 9:
133                 A_ON;
134                 B_OFF;
135                 C_OFF;
136                 break;
137             case 10:
138                 A_OFF;
139                 B_ON;
140                 C_OFF;
141                 break;
142             case 11:
143                 A_ON;
144                 B_ON;
145                 C_OFF;
146                 break;
147             case 12:
148                 A_OFF;
149                 B_OFF;
150                 C_ON;
151                 break;
152             case 13:
153                 A_ON;
154                 B_OFF;
155                 C_ON;
156                 break;
157             case 14:
158                 A_OFF;
159                 B_ON;
160                 C_ON;
161                 break;
162             case 15:
163                 A_ON;
164                 B_ON;
165                 C_ON;
166                 break;
167             default:
168                 break;
169         }
170         for(i=0;i<2000;i++);   //模拟开关切换之后需要等待一段时间来消除上一通道数据影响
171         //这个延时是根据测试所得,如果需要更好精度而不是速度的话可以加长延时
172     }
173     
174     GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);                             //拉低CS引脚电平
175     for(i=0;i<100;i++);                                                     //加入延时,速度过快则读不到数据
176     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET); 
177     SPI_I2S_SendData(SPI1,chanaddr);                                            //写入一个数据,包括采样通道和数据格式  
178     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==RESET) ;  
179     ADCdata=SPI_I2S_ReceiveData(SPI1); 
180     for(i=0;i<100;i++); 
181     ADCdata>>=4;                                                            //读取的数据为16位,低四位为0
182     GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);                                 //CS高 
183     
184     //在多通道采样时,当前读取的数据时上一次选择的通道值,如果在速度要求不高的情况下可以进行两次操作
185     GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);                             //拉低CS引脚电平
186     for(i=0;i<100;i++);                                                     //加入延时,速度过快则读不到数据
187     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET); 
188     SPI_I2S_SendData(SPI1,chanaddr);                                            //写入一个数据,包括采样通道和数据格式  
189     while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==RESET) ;  
190     ADCdata=SPI_I2S_ReceiveData(SPI1); 
191     for(i=0;i<100;i++); 
192     ADCdata>>=4;                                                            //读取的数据为16位,低四位为0
193     GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET); 
194     return ADCdata;
195 }
196 /*******************************************************************************
197 名称:void Write_DA(u16 chan,u16 data)
198 功能:向对应的通道写入数据
199 参数:chan对应的通道,取值0-3,data写入的数据取值0-4095
200 时间:2011.4.25
201 版本:1.0
202 注意:
203 *******************************************************************************/
204 void Write_DA(u16 chan,u16 data)
205 {
206     u16 Send_data,i;
207     for(i=0;i<50;i++);    
208     GPIO_WriteBit(GPIOB, GPIO_Pin_11, Bit_RESET); 
209     for(i=0;i<50;i++);    
210     //具体参照TLV5614数据手册,SPD位设置为1,设置为快速方式
211     Send_data=0x1000;
212     Send_data|=(chan<<14);
213     data&=0x0FFF;
214     Send_data|=data;
215     while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
216     SPI_I2S_SendData(SPI2,Send_data);
217     for(i=0;i<1200;i++);//上一句只是把数据写入发送的寄存器,实际上并没有发送完全
218     //因此这里并不能立刻拉高,这个延时是通过逻辑分析仪测试得到    
219     GPIO_WriteBit(GPIOB, GPIO_Pin_11, Bit_SET); //数据发送完成后先拉高帧同步信号
220     //按理说发送一遍应该可以了,实际测试有一个很奇怪的问题,就是连续发送四个通道数据
221     //的时候第二和第四通道数据发送不正确,于是这里干脆直接发送两遍。
222     for(i=0;i<50;i++);    
223     GPIO_WriteBit(GPIOB, GPIO_Pin_11, Bit_RESET);
224     while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET);
225     SPI_I2S_SendData(SPI2,Send_data);
226     for(i=0;i<1200;i++);    
227     GPIO_WriteBit(GPIOB, GPIO_Pin_11, Bit_SET); //数据发送完成后先拉高帧同步信号
228     
229 }

版权声明:本文为emouse原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/emouse/archive/2011/04/25/2198154.html