用 K60 的 UART 串口通信改变程序中的参数值

平时用单片机做东西免不了要调整一些参数,特别是调 PID 参数的时候,要不停得调整参数。如果一直通过烧程序改变参数的话,难免显得繁琐。因为最近在用 K60,所以今天我稍微研究了一下怎样通过 K60 的串口通信改变参数的值。

因为时间的原因,并没有看得很深入,没怎么看 K60 的底层寄存器,代码是借助拉普兰德的库写的。所以这篇文章就不涉及寄存器方面的东西了。


拉普兰德的例程中有串口中断的例程,但 UART 库函数的功能仅限于接收一个字符,这显然是不够用的,调整参数肯定要得到一个字符串。拉普兰德的库函数里有两种方法可以通过串口通信得到一个字符串。

一种方法是使用 K60 的 FIFO 功能,这种方法我没有细看。我用的是第二种方法,使用 K60 的 DMA 功能。

现在的任务是写出一个最简单的代码,上位机通过串口发送一个字符串给单片机,单片机得到这个字符串,简单处理一下就可以赋给参数值了,现在为了测试先将这个得到的字符串发送给上位机。

因为要用到 UART 功能和 DMA 功能,先定义结构体:

void uart_init()
{
  uart2_init_struct.UART_Uartx = UART2; //使用UART2
  uart2_init_struct.UART_BaudRate = 19200; //设置波特率19200
  uart2_init_struct.UART_RxPin = PTD2;  //接收引脚为PTD2
  uart2_init_struct.UART_TxPin = PTD3;  //发送引脚为PTD3

  uart2_init_struct.UART_RxIntEnable = 1 ;//开接收中断
  uart2_init_struct.UART_TxIntEnable = 1;    //使能发送中断

  uart2_init_struct.UART_RxDMAEnable = TRUE;    //使能接收DMA
  uart2_init_struct.UART_TxDMAEnable = TRUE;    //使能发送DMA
  //配置接收DMA
  uart_rev_dma_init_struct.DMA_CHx = DMA_CH0;                     //选择DMA CH0作为通道
  uart_rev_dma_init_struct.DMA_MajorLoopCnt   = LENGTH; //设置计数器长度为数组长度
  uart_rev_dma_init_struct.DMA_MinorByteCnt   = 1;                //设置每次的长度为byte
  uart_rev_dma_init_struct.DMA_MajorCompleteIntEnable = TRUE;     //设置DMA 计数器清零中断
  uart_rev_dma_init_struct.DMA_Req            = UART2_REV_DMAREQ; //设置DMA 请求为 UART rev
  uart_rev_dma_init_struct.DMA_DestAddr       = (uint32)recv_ram_buf; //设置目的地址为 recv_ram_buf
  uart_rev_dma_init_struct.DMA_DestAddrOffset = 1;                //每一次DMA请求,地址加1
  uart_rev_dma_init_struct.DMA_DestDataSize   = DMA_DST_8BIT;     //设置目的长度为byte
  uart_rev_dma_init_struct.DMA_SourceAddr     = (uint32)&UART2->D;//设置UART D为源地址
  uart_rev_dma_init_struct.DMA_SourceDataSize = DMA_SRC_8BIT;     //设置源长度为byte
  uart_rev_dma_init_struct.DMA_AutoDisableReq = 0;            //循环接收
  uart_rev_dma_init_struct.DMA_Isr = dma_isr;
  //配置发送DMA
  uart_trn_dma_init_struct.DMA_CHx = DMA_CH1;                     //选择DMA CH1作为通道
  uart_trn_dma_init_struct.DMA_MajorLoopCnt   = LENGTH; //设置计数器长度为数组长度
  uart_trn_dma_init_struct.DMA_MinorByteCnt   = 1;                //设置每次的长度为byte
  uart_trn_dma_init_struct.DMA_MajorCompleteIntEnable = FALSE;    //清空DMA 计数器清零中断
  uart_trn_dma_init_struct.DMA_Req            = UART2_TRAN_DMAREQ;//设置DMA 请求为 UART trn
  uart_trn_dma_init_struct.DMA_SourceAddr     = (uint32)recv_ram_buf; //设置源地址为 recv_ram_buf
  uart_trn_dma_init_struct.DMA_SourceAddrOffset = 1;               //每一次DMA请求,地址加1
  uart_trn_dma_init_struct.DMA_SourceDataSize = DMA_SRC_8BIT;     //设置源长度为byte
  uart_trn_dma_init_struct.DMA_DestAddr       = (uint32)&UART2->D;//设置UART D为目标地址
  uart_trn_dma_init_struct.DMA_DestDataSize   = DMA_DST_8BIT;     //设置目的长度为byte
  uart_trn_dma_init_struct.DMA_AutoDisableReq = 1;             //禁止循环发送
  uart_trn_dma_init_struct.DMA_Isr = dma_isr1;

  LPLD_DMA_Init(uart_rev_dma_init_struct); //初始化DMA 接收
  LPLD_DMA_Init(uart_trn_dma_init_struct); //初始化DMA 发送
  LPLD_DMA_EnableReq(DMA_CH0);         //使能DMA请求

  LPLD_DMA_EnableIrq(uart_rev_dma_init_struct);   //使能DMA CH0中断

  LPLD_UART_Init(uart2_init_struct);
}

中断函数:

void dma_isr()
{
  LPLD_DMA_EnableReq(DMA_CH1);         //使能DMA请求
  g_flag=1;
}

void dma_isr1()
{
  LPLD_DMA_DisableReq(DMA_CH1);
}

配置好后使能了 DMA_CH0,串口接收中断会进入 DMA 中断函数 dma_isr(),在里面使能 DMA 请求可以响应串口发送中断并进入 dma_isr1()。dma_isr()中的变量 g_flage 是全局变量用于标识发送了一次数据。用到的全局变量还有一个数组 uint8 recv_ram_buf[N],它用于保存上位机发送的字符串,注意 DMA 功能中配置了发送的字节数,只有发送的字符数目到了设定数目才会触发一次中断。

这样就已经可以完成一次功能了,不过 recv_ram_buf[] 数组在接收数据时地址会自动加一,发送第二个数据时新的数据并不会覆盖原先保存的数据,所以读取完数据后要重新设置发送的目标地址和接收的源地址,我是在主函数中重置的。可以用一个拨码开关控制数据的读取,并且我发送的数据第一位用固定的‘#’作为标志,代码如下:

if(PTBn_I(8)==0)
{
  if(g_flag==1)
  {
    DMA0->TCD[DMA_CH0].DADDR = DMA_DADDR_DADDR((uint32)recv_ram_buf);
    DMA0->TCD[DMA_CH1].SADDR = DMA_SADDR_SADDR((uint32)recv_ram_buf);
    if(recv_ram_buf[0]=='#')
      num_output=atoi(recv_ram_buf);
    g_flag=0;
  }
  OutData[0]=num_output;
  OutPut_Data();
}

atoi()函数用于将获得的字符串转换为 int 型的数据保存,就是这样改变参数的值得。现在可以通过串口示波器观察得到的数值是否就是我们发送的数值。

之后可以在发送的数据中再加入标志位用来表示要改变什么参数,这样就可以用串口改变各个参数的值了。

你可能感兴趣的:(单片机)