在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
https://www.cnblogs.com/yangfengwu/p/7520260.html
重点是说SPI通信协议,,,, 不要害怕协议因为协议是人规定的,,刚好我也是人......规定的协议既然能成为规范让所有人所接受,那么必然有它的优势和优点,必然值得学习,, 害怕协议的人是因为当初碰到了不懂的老师,他只会告诉你这很难............其实是他不会........
CS : Chip Selection 片选引脚,多个设备时可以用这个引脚选择和哪个设备通信 MOSI : Master Out Slave In 主机输出数据引脚,,,,从机接收数据引脚 MISO : Master In Slave Out 主机接收数据引脚....从机输出数据引脚 CLK : 时钟 还有两个参数----假设有的单片机自带硬件SPI,一定会提供设置下面两个参数,,,当然有的支持SPI通信的芯片也可能涉及这两个参数 CPOL :表示时钟信号(CLK引脚)在空闲时是高电平还是低电平 CPHA :表示数据在时钟信号(CLK)的第几个沿开始数据传输 现在假如说 CPOL = 0 ;//时钟信号(CLK引脚)在空闲时是低电平 CPHA = 0;//数据在时钟信号(CLK)的第1个沿开始数据传输
通信的时候先传输高位 假如说 主机发给从机 10101010 从机发给主机 01010101 再假如 主机接收数据存到 MasterData 里面 从机接收数据存到 SlaveData 里面
第一个上升沿 主机的10101010 最高位是 1 所以主机会让MOSI引脚输出高电平 从机的01010101最高位是 0 所以从机会让MISO引脚为低电平
第一个下降沿 主机接收MISO引脚的数据,因为是低电平所以 MasterData= 0000 0000; 从机接收MOSI引脚的数据,因为是高电平所以从机SlaveData = 0000 0001;
第二个上升沿 主机左移一位 0101010X 最高位是 0 所以主机会让MOSI引脚输出低电平 从机左移一位 1010101X 最高位是 1 所以从机会让MISO引脚为高电平
第二个下降沿 主机接收MISO引脚的数据,因为是高电平所以 MasterData= 0000 0001; 从机接收MOSI引脚的数据,因为是低电平所以从机SlaveData = 0000 0010;
就这样8个上升和8个下降沿之后 MasterData = 01010101 SlaveData = 10101010
现在假如说 CPOL = 0 ;//时钟信号(CLK引脚)在空闲时是低电平 CPHA = 1;//数据在时钟信号(CLK)的第2个沿开始数据传输
第一个下降沿 主机的10101010 最高位是 1 所以主机会让MOSI引脚输出高电平 从机的01010101最高位是 0 所以从机会让MISO引脚为低电平
第一个上升沿 (注意是标号为1的那个,,,实际上是第二个上升沿) 主机接收MISO引脚的数据,因为是低电平所以 MasterData= 0000 0000; 从机接收MOSI引脚的数据,因为是高电平所以从机SlaveData = 0000 0001;
第二个下降沿 主机左移一位 0101010X 最高位是 0 所以主机会让MOSI引脚输出低电平 从机左移一位 1010101X 最高位是 1 所以从机会让MISO引脚为高电平
第二个上升沿 主机接收MISO引脚的数据,因为是高电平所以 MasterData= 0000 0001; 从机接收MOSI引脚的数据,因为是低电平所以从机SlaveData = 0000 0010;
第八个下降沿 主机把最后一位0放在了 MOSI引脚输出低电平 从机把最后一位1放在了 MISO引脚输出高电平
其实现在我也有疑惑,,,这样就完了吗??????只把数据放在引脚上就行了吗????然后内部硬件就自动接收了吗???? 看一下摩托罗拉的数据手册
难道最后一位会自动的接收?????搞不懂咧咧.....改天自己测试一下,,,让主机工作在 CPOL = 0 ;//时钟信号(CLK引脚)在空闲时是低电平 CPHA = 1;//数据在时钟信号(CLK)的第2个沿开始数据传输 然后让主机发一个字节的数据看看CLK怎样变化的..............然后再尝试手写从机接收....然后知道结果了再来修改这个地方.... 其余的两种就不说了 其实说白了就是 CPOL控制在空闲状态下CLK是高电平还是低电平 CPHA控制数据是在第一个沿就开始传输还是在第二个沿 其实呢!!写程序最终还是要看芯片的资料,,,,, 现在看一下ESP8266的SPI
spi.setup(1, spi.MASTER, spi.CPOL_HIGH, spi.CPHA_HIGH, 8, 8) 用SPI1,主机模式,,空闲状态下Clk为高电平,,第二个沿开始数据传输,8位数据,8分频(10Mhz),默认半双工 发送数据呢就简单了 比如向从机发送0xaa,0x55,0x02,0x01
spi.send(1,0xaa,0x55,0x02,0x01)
接收数据呢还另有个函数
ReadData = spi.recv(1,4,0xaa) 其实就是让CLK产生32个脉冲信号,每8个代表一个字节的数据,,后面的0xaa哈,是在产生脉冲信号的时候MOSI引脚发送的数据,,如果不写 默认发0xFF
对了接收到的数据都是以字符串的形式保存在变量里面,,可能会问我怎么自己解析数据呢 假如说判断是不是接收到0xaa 和0x55 aa = spi.recv(1,2,0xaa) if aa:byte(1)==0xaa and aa:byte(2)==0x55 then 自己的执行函数 end 大家肯定会说你咋知道要这样写 因为有API文档
还有一点,,我一开始看到过别人这样做过,,所以呢我就知道可以这样用....知识这东西一定要活学活用 http://blog.csdn.net/silno/article/details/72866623?locationNum=10&fps=1
最后说一下和STM32进行SPI通信的一些注意,,,当然是把stm32配置成从机模式,,然后呢其余的设置一定要一样 列如我配置的 void Spi2SlaveInit(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//CS GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOB,&GPIO_InitStructure); //GPIO_ResetBits(GPIOB,GPIO_Pin_12); //PB13/14/15上拉 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_ResetBits(GPIOB,GPIO_Pin_14); //PB13/14/15上拉 GPIO_ResetBits(GPIOB,GPIO_Pin_15); //PB13/14/15上拉 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; //如果这里使用硬件模式,从机低电平 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI2, &SPI_InitStructure); SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE); SPI_Cmd(SPI2 , ENABLE); }
要注意 CS引脚在模块刚启动的时候一定是低电平............ 再说一点,我的32程序用的中断接收的SPI的数据,然后在中断里面准备发送的数据,,大家这样想 主机的数据发过来一个字节数据之后才进的中断,,所以如果想在中断里面发送数据,,应该在进中断之前准备好数据的第一个字节 假设主机需要读四个字节就会进四次中断 我从机发给主机的数据是0xaa 0x55 0x01 0x02 char table[4] = {0xaa, 0x55, 0x01, 0x02} 在主机发送数据之前 我需要 SPI2->DR = table; Spi2SendBuff = table+1; void SPI2_IRQHandler(void) { if(SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET) { SPI2->DR = *Spi2SendBuff; Spi2ReadBuff[Spi2ReadCnt] = SPI2->DR; Spi2ReadCnt ++; Spi2SendBuff ++; } } 这样的话来第一个中断的时候我的第一个数据0xaa也发向了主机,然后又准备了第二个数据,,,,,,,四次中断就会把数据发给了主机,,注意指针溢出乱指了一下 这篇文章呢主要是会用ESP8266的SPI就行哈...... https://www.cnblogs.com/yangfengwu/p/7524326.html |
请发表评论