当前位置: 首页 > news >正文

工程师 - Raspberry Pi Pico程序:读取SPI数据后从串口输出

1,通过Arduino IDE编写代码,并使用Pico C SDK。编译后烧写到Pico板卡中。

使用SPI1,端子号为GPIO 10, 12, 13, 15.

SPI的波特率为400K。

UART设置为500K。

2,第一个版本,将数据以16bit单位的十进制数值形式打印出来

SPI读取单位为2个字节,长度为8.

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include <stdio.h>

#include "hardware/irq.h"

#include "hardware/structs/spi.h"

#include "hardware/resets.h"

void setup() {

  Serial.begin(500000);

  gpio_set_function(10, GPIO_FUNC_SPI);

  gpio_set_function(12, GPIO_FUNC_SPI);

  gpio_set_function(13, GPIO_FUNC_SPI);

  gpio_set_function(15, GPIO_FUNC_SPI);

  spi_init(spi1, 400000);

  spi_set_format(spi1,16,SPI_CPOL_1,SPI_CPHA_1,SPI_MSB_FIRST);

  spi_set_slave(spi1, 1);  

  irq_set_exclusive_handler(SPI1_IRQ, my_spi_handler);

  irq_set_enabled(SPI1_IRQ, true);

  irq_set_priority(SPI1_IRQ,0);

  spi1_hw->imsc = 1 << 2;

}

uint16_t recvBuff[8];

volatile bool recvBuffReady = false;

void my_spi_handler() {

  spi_read16_blocking(spi1, 0, recvBuff, 8);

  recvBuffReady = true;

}

void loop() {

  if (recvBuffReady) {

    recvBuffReady = false;

    for (int i = 0; i < 8; i++)

    {

      Serial.print(recvBuff[i]);

      Serial.printf(",");

    }

    Serial.println();

  }

}

2,修改一下输出格式。

第一个版本的工作情况,master发送是16x2个字节发送一次。Pico板作为slave,是8x2读取一次,把数据存下来。

输入的二进制数据格式,输出时,每2个字节作为一个数值打印成十进制格式,会比较长。

然后loop里面把一次读取的再发出去。读取发送的节奏是可控的,发一次,读两次,正好。

而如果Master连续发送数据的话,这个程序运行状态就不一样了。发送读取节奏不一致了,一次读满8个字节,可能会超时。

而且我们要输出的主要是连续的可打印的字符串,输出每个字符调用write函数即可。

第二个版本的修改,SPI读取单位改为1个字节,长度为8.

串口输出改为write函数。

不过发现有些数据是乱码,或者会丢失。

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include <stdio.h>

#include "hardware/irq.h"

#include "hardware/structs/spi.h"

#include "hardware/resets.h"

void setup() {

  Serial.begin(500000);

  gpio_set_function(10, GPIO_FUNC_SPI);

  gpio_set_function(12, GPIO_FUNC_SPI);

  gpio_set_function(13, GPIO_FUNC_SPI);

  gpio_set_function(15, GPIO_FUNC_SPI);

  spi_init(spi1, 400000);

  spi_set_format(spi1,8,SPI_CPOL_1,SPI_CPHA_1,SPI_MSB_FIRST);

  spi_set_slave(spi1, 1);  

  irq_set_exclusive_handler(SPI1_IRQ, my_spi_handler);

  irq_set_enabled(SPI1_IRQ, true);

  irq_set_priority(SPI1_IRQ,0);

  spi1_hw->imsc = 1 << 2;

}

uint8_t recvBuff[8];

volatile bool recvBuffReady = false;

void my_spi_handler() {

  spi_read_blocking(spi1, 0, recvBuff, 8);

  recvBuffReady = true;

}

void loop() {

  if (recvBuffReady) {

    recvBuffReady = false;

    for (int i = 0; i < 8; i++)

    {

      Serial.write(recvBuff[i]);

    }

  }

}

3,使用中断发送数据。

试验了下,开始传输是OK的,发了几十个字节之后就不好用了。

有可能是在中断里调用串口的写操作会引发不可知的影响。

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include <stdio.h>

#include "hardware/irq.h"

#include "hardware/structs/spi.h"

#include "hardware/resets.h"

void setup() {

Serial.begin(500000);

gpio_set_function(10, GPIO_FUNC_SPI);

gpio_set_function(12, GPIO_FUNC_SPI);

gpio_set_function(13, GPIO_FUNC_SPI);

gpio_set_function(15, GPIO_FUNC_SPI);

spi_init(spi1, 400000);

spi_set_format(spi1,8,SPI_CPOL_1,SPI_CPHA_1,SPI_MSB_FIRST);

spi_set_slave(spi1, 1);

irq_set_exclusive_handler(SPI1_IRQ, my_spi_handler);

irq_set_enabled(SPI1_IRQ, true);

irq_set_priority(SPI1_IRQ,0);

}

uint8_t recvBuff[5];

void my_spi_handler() {

spi_read16_blocking(spi1, 0, recvBuff, 1);

Serial.write(recvBuff[0]);

}

void loop() {

}

4,直接在loop里通过中断设置flag,或者判断是否数据可读,来收取数据,都没有输出。

这个是因为时序控制不对,中断里你不读数据,到了loop里就来不及了,读不到了把。

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include <stdio.h>

#include "hardware/irq.h"

#include "hardware/structs/spi.h"

#include "hardware/resets.h"

bool flag_readable;

uint8_t recvBuff[5];

void setup() {

  Serial.begin(500000);

  gpio_set_function(10, GPIO_FUNC_SPI);

  gpio_set_function(12, GPIO_FUNC_SPI);

  gpio_set_function(13, GPIO_FUNC_SPI);

  gpio_set_function(15, GPIO_FUNC_SPI);

  spi_init(spi1, 400000);

  spi_set_format(spi1,8,SPI_CPOL_1,SPI_CPHA_1,SPI_MSB_FIRST);

  spi_set_slave(spi1, 1);  

  irq_set_exclusive_handler(SPI1_IRQ, my_spi_handler);

  irq_set_enabled(SPI1_IRQ, true);

  irq_set_priority(SPI1_IRQ,0);

  spi1_hw->imsc = 1 << 2;

  flag_readable = false;

}

void my_spi_handler() {

  flag_readable = true;

}

void loop() {

  if(spi_is_readable(spi1)){

    flag_readable = false;

    spi_read_blocking(spi1, 0, recvBuff, 1);

    Serial.write(recvBuff[0]);

  }

}

5,使用ringbuffer函数来读取数据,然后loop里进行发送。

Ring Buffer里的buffer大小是250,这里使用大小100的buffer去读取,然后输出。

#include "pico/stdlib.h"

#include "hardware/spi.h"

#include <stdio.h>

#include "hardware/irq.h"

#include "hardware/structs/spi.h"

#include "hardware/resets.h"

#include "ringbuffer.h"

RingBuffer rb;

#define BUF_LEN 100

uint8_t buffer[BUF_LEN];

void setup() {

  Serial.begin(500000);

  gpio_set_function(10, GPIO_FUNC_SPI);

  gpio_set_function(12, GPIO_FUNC_SPI);

  gpio_set_function(13, GPIO_FUNC_SPI);

  gpio_set_function(15, GPIO_FUNC_SPI);

  spi_init(spi1, 400000);

  spi_set_format(spi1,8,SPI_CPOL_1,SPI_CPHA_1,SPI_MSB_FIRST);

  spi_set_slave(spi1, 1);  

  irq_set_exclusive_handler(SPI1_IRQ, my_spi_handler);

  irq_set_enabled(SPI1_IRQ, true);

  irq_set_priority(SPI1_IRQ,0);

  // Enable receive FIFO half full and receive FIFO read timeout interrupt

  spi1_hw->imsc = 1  | (1 << 2);

  RingBuffer_Init(&rb);

}

void my_spi_handler() {

  uint8_t data;

  

  // Clear the receive FIFO read timeout interrupt status

  if(spi1_hw->ris | SPI_SSPRIS_RTRIS_BITS){

    spi1_hw->icr = SPI_SSPICR_BITS;

  }

  while(spi_is_readable(spi1)){

    spi_read_blocking(spi1, 0, &data, 1);

    RingBuffer_Write(&rb, &data, 1);

  }

}

void loop() {

  uint16_t len = RingBuffer_GetDataLength(&rb);

  uint8_t data;

  if (len > 0) {

      if(len > BUF_LEN) len = BUF_LEN;

      RingBuffer_Read(&rb, buffer, len);

      Serial.write(buffer, len);

   

  }

  else{

    /* If receive fifo is not empty, read the data */

    if(spi1_hw->sr | SPI_SSPSR_RNE_BITS){

      if(spi_is_readable(spi1)){

        spi_read_blocking(spi1, 0, &data, 1);

        RingBuffer_Write(&rb, &data, 1);

      }  

    }

  }

}

备注:

1,接SPI信号线来抓取SPI数据,两边的地线最好也能接到一起,不然信号还是有些不稳定的。比如在没有通信时,还是会打印出乱码数据。

就这种:�����

http://www.dtcms.com/a/452834.html

相关文章:

  • 虚幻引擎5 GAS开发俯视角RPG游戏 P04-12 可缩放浮点数的曲线表
  • 接口请求工具对比 apifox apipost swagger postman等
  • C++联合体(Union)详解:与结构体的区别、联系与深度解析
  • LangChain部署RAG part2.搭建多模态RAG引擎(赋范大模型社区公开课听课笔记)
  • SSM--day4--SpringMVC(补充)
  • Flink Checkpoint与反压问题排查手册:从日志分析到根因定位
  • 元宇宙的教育应用:重构学习体验与知识传递
  • 建设99网站江西网站开发哪家好
  • RabbitMQ高可用集群搭建教程(基于CentOS 7.9 + Erlang 23.2.7 + RabbitMQ 3.8.8)
  • 【LangChain】P14 LangChain 输出解析器深度解析:Json解析器、XML解析器、字符串及列表、日期解析器
  • 仿真软件-多机器人2
  • 《基于 ERT 的稀疏电极机器人皮肤技术》ICRA2020论文解析
  • 聚焦CRISPR技术配套工具链的开源生态建设
  • 网站做视频窗口接口收费么免费搭建自己的网站
  • ​​Avalonia UI 开发核心注意事项:从理念到部署的避坑指南​
  • 从chatGPT获取的关于相机焦距与其他参数的关系
  • 拒绝做网站的理由wordpress自适应 slide
  • 【IT老齐456】Spring Boot优雅开发多线程应用,笔记01
  • 网站收录怎么弄极路由4 做网站
  • 备考华为HCIA - 云计算,培训与自学到底该怎么选?
  • 106、23种设计模式之备忘录模式(15/23)
  • LangChain部署rag Part3olmOCR与MinerU工具(赋范大模型社区公开课听课笔记)
  • C++进阶:使用普通函数重载算数运算符
  • 从内核调优到集群部署:基于Linux环境下KingbaseES数据库安装指南
  • Micro850 控制器深度解析:硬件特性与 I/O 接线核心(罗克韦尔2)
  • Python oct() 函数
  • (一) 机器学习之深度神经网络
  • C语言指针全面解析:从内存管理到高级应用
  • 南通网站建设推广专家建站教程的优点
  • Spring Boot整合Apache Shiro权限认证框架(应用篇)