- 打卡等级:偶尔看看III
- 打卡总天数:31
- 最近打卡:2025-10-30 13:40:00
已绑定手机
中级会员
- 积分
- 209
|
#include "encoder.h"
#include "sys_tick.h"
#include <string.h>
// 引脚定义(TLE5012与AI8051U连接)
#define CS P14 // TLE5012 CS引脚(P1.4)
#define SPI_MOSI P15
#define SPI_MISO P16
#define SPI_SCK P17
// -------------------------- TLE5012命令修正(符合协议) --------------------------
// 1. 基础读命令(Lock=0000B,地址0x00~0x04,2字节命令)
uint8 xdata TLE5012_CMD_UNLOCK[] = {0x60,0x00}; // 写解锁命令(必须先发,否则写入无效)
uint8 xdata TLE5012_CMD_READ_STATUS[] = {0x80, 0x01}; // 读状态(0x00,返回2字节)
uint8 xdata TLE5012_CMD_READ_ANGLE[] = {0x80, 0x41}; // 读角度(0x01,返回2字节)
uint8 xdata TLE5012_CMD_READ_TEMP[] = {0x80, 0x02}; // 读温度(0x02,返回2字节)
uint8 xdata TLE5012_CMD_READ_SPEED[] = {0x80, 0x03}; // 读速度(0x03,返回2字节)
uint8 test[]={0xd0,0x82};
// -------------------------- 数据缓冲区定义(修正大小) --------------------------
uint8 xdata encoder_tx_buf[5] = {0}; // SPI发送缓冲区(存命令)
uint8 xdata encoder_rx_buf[5] = {0}; // SPI接收缓冲区(存回复+数据)
uint8 xdata encoder_angle_buf[2] = {0}; // DMA接收缓冲区(存回复+数据)
uint8 Read_register_num = 0; // 读取寄存器数量
// 解析后的数据(添加有效性标志)
float encoder_angle = 0; // 角度(0~4095→0~360°,12位有效)
int16 xdata encoder_speed = 0; // 速度(RPM,16位有符号)
int16 xdata encoder_temp = 0; // 温度(℃,需换算)
uint16 xdata encoder_status = 0; // 状态(判断校准是否完成)
bit B_ENCODER_DATA_VALID = 0; // 数据有效标志
// 控制标志
bit B_ENCODER_DMA_BUSY = 0; // DMA忙标志
bit B_ENCODER_CAL_DONE = 0; // 校准完成标志
bit B_ENCODER_TIMEOUT = 0; // 超时标志
bit B_ENCODER_NEXT_DMA_MODE = 0; // 下一次DMA模式标志位 0:DMA接收 1:DMA完成
// 超时时间记录
uint32 xdata encoder_timeout_start = 0;
// 超时相关定义
uint8 xdata ENCODER_TIMEOUT_MS = 10; // 超时时间(毫秒)
// -------------------------- SPI初始化 --------------------------
void Encoder_SPI_Init(void)
{
SPCTL = 0x01;
SSIG = 1; //1: 忽略SS脚,由MSTR位决定主机还是从机 0: SS脚用于决定主机还是从机。
SPEN = 1; //1: 允许SPI, 0:禁止SPI,所有SPI管脚均为普通IO
DORD = 0; //1:LSB先发, 0:MSB先发
MSTR = 1; //1:设为主机 0:设为从机
CPOL = 0; //1: 空闲时SCLK为高电平, 0:空闲时SCLK为低电平
CPHA = 1; //1: 数据在SCLK前沿驱动,后沿采样. 0: 数据在SCLK前沿采样,后沿驱动.
P_SW1 = (P_SW1 & ~0x0c) | ((0<<2) & 0x0c); //切换IO
//sck P17 推挽输出 高速模式
P1M0 |= 0x80;
P1M1 &= 0x7F;
P1SR &= ~0x80;
//cs P14 推挽输出
P1M0 |= 0x10;
P1M1 &= 0xEF;
P1SR &= ~0x10;
//mosi P15 开漏输出,方便单线读写,写1可释放总线
P1M0 |= 0x20;
P1M1 |= 0x20;
//sck cs大电流驱动
P1DR &= ~0x90;
//打开MISO、MOSI的上拉电阻
P1PU |= 0x60;
}
//初始化为DMA发送模式
void DMA_Encoder_SPI_Init(void)
{
// 1. 停止当前DMA(避免残留操作)
DMA_SPI_CR = 0x00;
DMA_SPI_STA = 0x00; // 清除发送完成状态标志
// 2. 配置DMA缓冲区地址
DMA_SPI_TXAH = (uint8)((uint16)encoder_tx_buf >> 8); // 发送缓冲区高字节
DMA_SPI_TXAL = (uint8)((uint16)encoder_tx_buf); // 发送缓冲区低字节
DMA_SPI_RXAH = (uint8)((uint16)encoder_rx_buf >> 8); // 接收缓冲区高字节
DMA_SPI_RXAL = (uint8)((uint16)encoder_rx_buf); // 接收缓冲区低字节
// 3. DMA核心配置
// 使能中断+同时使能TX+优先级2+数据优先级3
DMA_SPI_CFG = 0x00;// 先清零
system_delay_ms(1);
DMA_SPI_CFG = (1<<7) | (1<<6);//使能中断+同时使能TX
DMA_SPI_CFG |= 0x0B; // 优先级2+数据优先级3
// 不自动控制SS脚(CS手动控制),文档34.4.9节DMA_SPI_CFG2
DMA_SPI_CFG2 = (0<<2) | 0;
B_ENCODER_NEXT_DMA_MODE = 0; // 置标志位为DMA发送模式
}
void ENCODER_SPI_DMA_Tx(uint8 xdata *TxBuf, uint8 tx_len)
{
B_ENCODER_DMA_BUSY = 1; // 置忙标志
B_ENCODER_TIMEOUT = 0; // 清超时标志
//关闭DMA以防冲突
DMA_SPI_CR = 0x00;
//拉低CS开始传输
CS = 0;
// 1. 更新发送缓冲区地址(若TxBuf变化)
if (TxBuf != encoder_tx_buf)
{
DMA_SPI_TXAH = (uint8)((uint16)TxBuf >> 8);
DMA_SPI_TXAL = (uint8)((uint16)TxBuf);
}
// 2. 配置传输长度(文档34.4.4节:总字节数=实际长度-1)
DMA_SPI_AMTH = (uint8)((tx_len - 1) / 256);
DMA_SPI_AMT = (uint8)((tx_len - 1) % 256);
// 3. 清除标志并启动DMA(文档34.4.4节DMA_SPI_CR)
DMA_SPI_STA = 0x00;
DMA_SPI_CR = (1<<7) | (1<<6) | 1; // DMA_ENSPI=1 + SPI_TRIG_M=1 + SPI_CLRFIFO=1
}
void ENCODER_SPI_DMA_Rx(uint8 xdata *RxBuf, uint8 rx_len)
{
B_ENCODER_DMA_BUSY = 1; // 置忙标志
B_ENCODER_TIMEOUT = 0; // 清超时标志
//关闭DMA以防冲突
DMA_SPI_CR = 0x00;
// 1. 更新接收缓冲区地址(若RxBuf变化)
if (RxBuf != encoder_rx_buf)
{
DMA_SPI_RXAH = (uint8)((uint16)RxBuf >> 8);
DMA_SPI_RXAL = ((uint16)RxBuf & 0x00FF);
}
// 2. 配置接收长度(文档34.4.4节:总字节数=实际长度-1)
DMA_SPI_AMTH = (uint8)((rx_len - 1) / 256);
DMA_SPI_AMT = (uint8)((rx_len - 1) % 256);
// 3. 清除标志并启动DMA(文档34.4.4节DMA_SPI_CR)
DMA_SPI_STA = 0x00;
DMA_SPI_CR = (1<<7) | (1<<6) | 1; // DMA_ENSPI=1 + SPI_TRIG_M=1 + SPI_CLRFIFO=1
}
// -------------------------- TLE5012写寄存器 --------------------------
void TLE5012_Write(uint8 reg,uint8 dat)
{
}
// -------------------------- TLE5012读寄存器 --------------------------
void TLE5012_Read(uint8 reg,uint8 reg_num)
{
// 构造读命令1_0000_0_ADDR_ND
//读(1)_Lock(4)_UPD(1)__ADDR(6)_ND(4)
encoder_tx_buf[0] = (uint8)TLE5012_READ_CMD<<7;
encoder_tx_buf[1] = (reg<<4)|(reg_num<<0); // 第二字节补全命令格式
// 启动DMA发送命令
ENCODER_SPI_DMA_Tx(encoder_tx_buf, 2);
Read_register_num = reg_num;
}
// -------------------------- 编码器初始化(整合SPI/DMA/校准) --------------------------
void encoder_init(void)
{
Encoder_SPI_Init();
DMA_Encoder_SPI_Init();
}
// -------------------------- 启动连续读取(优化CS时序) --------------------------
void encoder_start_continuous_read(void)
{
}
// -------------------------- 数据解析(修正越界与有效性) --------------------------
void encoder_parse_data(void)
{
// 2. 解析角度(0x01寄存器,高12位有效)
encoder_angle = (float)360/32768.0 * (((encoder_angle_buf[0]&0x7F) << 8) | encoder_angle_buf[1]);
B_ENCODER_DATA_VALID = 1;
}
// -------------------------- 超时检测函数 --------------------------
void encoder_check_timeout(void)
{
if (B_ENCODER_TIMEOUT) {
B_ENCODER_TIMEOUT = 0;
// 通过USB输出超时信息
printf_usb("Encoder communication timeout!\r\n");
}
}
//DMA转运完成中断服务程序
void ENCODER_SPI_DMA_ISR(void) interrupt DMA_SPI_VECTOR
{
// 1. 清除中断标志(文档强制要求,避免重复触发)
DMA_SPI_STA = 0;
// 2. 释放忙标志
B_ENCODER_DMA_BUSY = 0;
if(!B_ENCODER_NEXT_DMA_MODE) //下一次DMA模式为接收
{
// rgb_set_color_state(RGB_COLOR_BLUE, RGB_STATE_BREATH); // 设置RGB状态为蓝色呼吸灯,表示首次发送数据
P15 = 1; //释放MOSI总线,准备接收数据
system_delay_ms(1); //短延时,确保总线稳定
ENCODER_SPI_DMA_Rx(encoder_rx_buf, (Read_register_num+1)*2);
B_ENCODER_NEXT_DMA_MODE = 1;
//关闭DMA
DMA_SPI_CR = 0x00;
}
else{ //DMA接收完成
B_ENCODER_NEXT_DMA_MODE = 0;
//解析数据
encoder_parse_data();
// rgb_set_color_state(RGB_COLOR_RED, RGB_STATE_BREATH);
//拉高CS结束传输
CS = 1;
//关闭DMA
DMA_SPI_CR = 0x00;
}
}
下面是调用
TLE5012_Read(TLE5012_ANGLE_VALUE_AVAL_ADDR,1); // 读取角度寄存器
|
|