LCD和SRAM同时工作测试代码
就这么一个实验,同时工作不冲突。
工程包含了LCD的驱动和SRAM驱动。Ctrl+F5直接运行即可。
本来想加入串口程序,后来有问题就删掉了。有兴趣的童鞋可以加进去吧用电脑件事SRAM的数据读写
工程使用12M晶振,使用8M晶振的童鞋需要改一下。更改方式请参看jobs的进程贴
代码包如下:
http://share.eepw.com.cn/share/download/id/75363


102楼
一晚上,试验dac输出wav。没搞定,郁闷。没有示波器,看输出完全靠耳朵,真麻烦啊。暂停mp3解码,等时机到了,工具全了再来搞。

103楼
开始玩CAN
晚上弄了下CAN 准备实现LoopBack模式的数据收发。就是自己收自己发送的数据。
LoopBack是CAN控制器的一种工作模式。板子只有一个CAN控制器,而且电阻也焊错了(原理图错误)。现在只能使用这种模式了。
在STM32参考手册里边的地428页这么讲的:
通过对CAN_BTR寄存器的LBKM位置’1’,来选择环回模式。在环回模式下,bxCAN把发送的报
文当作接收的报文并保存(如果可以通过接收过滤)在接收邮箱里。
环回模式可用于自测试。为了避免外部的影响,在环回模式下CAN内核忽略确认错误(在数据/远
程帧的确认位时刻,不检测是否有显性位)。在环回模式下,bxCAN在内部把Tx输出回馈到Rx输
入上,而完全忽略CANRX引脚的实际状态。发送的报文可以在CANTX引脚上检测到。
这只是一种只检测模式。
这种模式工作示意图如下:

如果有示波器,还可以看见CAN发送引脚的波形输出
今天只是学习下,没代码
晚上弄了下CAN 准备实现LoopBack模式的数据收发。就是自己收自己发送的数据。
LoopBack是CAN控制器的一种工作模式。板子只有一个CAN控制器,而且电阻也焊错了(原理图错误)。现在只能使用这种模式了。
在STM32参考手册里边的地428页这么讲的:
通过对CAN_BTR寄存器的LBKM位置’1’,来选择环回模式。在环回模式下,bxCAN把发送的报
文当作接收的报文并保存(如果可以通过接收过滤)在接收邮箱里。
环回模式可用于自测试。为了避免外部的影响,在环回模式下CAN内核忽略确认错误(在数据/远
程帧的确认位时刻,不检测是否有显性位)。在环回模式下,bxCAN在内部把Tx输出回馈到Rx输
入上,而完全忽略CANRX引脚的实际状态。发送的报文可以在CANTX引脚上检测到。
这只是一种只检测模式。
这种模式工作示意图如下:

如果有示波器,还可以看见CAN发送引脚的波形输出
今天只是学习下,没代码

104楼
连着上了几天班,早出晚归的一直没时间弄板子。
今天参考野火程序,弄了下CAN。还不错 Loopback模式正常收发数据。
配置CAN为中断接收模式
参考了野火的程序实现。
这里基本就是我对野火程序的理解,和拷贝
1、设置NVIC 使能CAN中断接收
static void CAN_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable CAN1 RX0 interrupt IRQ channel */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 主优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2、引脚GPIO设置
板子上的CAN引脚被从定义到了PB8和PB9.
需要使用AFIO的Renap功能
static void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
/* CAN1 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* Configure CAN pin: RX */ // PB8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure CAN pin: TX */ // PB9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
//将CAN1引脚重定义到PB8 PB9 使用引脚服用功能
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
}
3、将CAN配置为LoopBack模式
配置完成后发送一帧数据,并接收。以检查是否配置成功,此处的接收使用了查询方式
TestStatus CAN_Polling(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
CanRxMsg RxMessage;
uint32_t i = 0;
uint8_t TransmitMailbox = 0;
/* CAN register init */
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE; // 时间触发通信禁止
CAN_InitStructure.CAN_ABOM=DISABLE; // 离线退出是在中断置位清0后退出
CAN_InitStructure.CAN_AWUM=DISABLE; // 自动唤醒模式:清零sleep
CAN_InitStructure.CAN_NART=DISABLE; // 自动重新传送豹纹,知道发送成功
CAN_InitStructure.CAN_RFLM=DISABLE; // FIFO没有锁定,新报文覆盖旧报文
CAN_InitStructure.CAN_TXFP=DISABLE; // 发送报文优先级确定:标志符
CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; // 回环模式
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // 1tq、BS1、BS2的值跟波特率有关
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=5; // 分频系数为5
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
/* CAN 过滤器初始化 */
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //标识符过滤
//使用32位过滤器,接收报文标识符的每一位都必须跟过滤器标识符相同
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //设置标识符
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0; //接收FIFO
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能过滤器
CAN_FilterInit(&CAN_FilterInitStructure);
/* transmit */
TxMessage.StdId=0x11; // 设定标准标识符(11位,扩展的为29位)
TxMessage.RTR=CAN_RTR_DATA; // 传输消息的帧类型为数据帧(还有远程帧)
TxMessage.IDE=CAN_ID_STD; // 消息标志符实验标准标识符
TxMessage.DLC=2; // 发送两帧,一帧8位
TxMessage.Data[0]=0xCA; // 第一帧数据
TxMessage.Data[1]=0xFE; // 第二帧数据
TransmitMailbox=CAN_Transmit(CAN1, &TxMessage); //处理好数据后,将数据贞挂号等待发送。
i = 0;
// 用于检查消息传输是否正常
while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFF))
{
i++;
}
i = 0;
// 检查返回的挂号的信息数目
while((CAN_MessagePending(CAN1, CAN_FIFO0) < 1) && (i != 0xFF))
{
i++;
}
/* receive */
RxMessage.StdId=0x00;
RxMessage.IDE=CAN_ID_STD;
RxMessage.DLC=0;
RxMessage.Data[0]=0x00;
RxMessage.Data[1]=0x00;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
if (RxMessage.StdId!=0x11)
{
return FAILED;
}
if (RxMessage.IDE!=CAN_ID_STD)
{
return FAILED;
}
if (RxMessage.DLC!=2)
{
return FAILED;
}
/* 判断发送的信息和接收的信息是否相等 */
if ((RxMessage.Data[0]<<8|RxMessage.Data[1])!=0xCAFE)
{
return FAILED;
}
//printf("receive data:0X%X,0X%X",RxMessage.Data[0], RxMessage.Data[1]);
return PASSED; /* Test Passed */
}
4、配置CAN的中断接收
TestStatus CAN_Interrupt(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
uint32_t i = 0;
/* CAN register init */
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE; // 时间触发通信禁止
CAN_InitStructure.CAN_ABOM=DISABLE; // 离线退出是在中断置位清0后退出
CAN_InitStructure.CAN_AWUM=DISABLE; // 自动唤醒模式:清零sleep
CAN_InitStructure.CAN_NART=DISABLE; // 自动重新传送豹纹,知道发送成功
CAN_InitStructure.CAN_RFLM=DISABLE; // FIFO没有锁定,新报文覆盖旧报文
CAN_InitStructure.CAN_TXFP=DISABLE; // 发送报文优先级确定:标志符
CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; // 回环模式
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // 1tq、BS1、BS2的值跟波特率有关
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=1; // 分频系数为1
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
/* CAN filter init */
CAN_FilterInitStructure.CAN_FilterNumber=1;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
/* CAN FIFO0 message pending interrupt enable */
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //中断使能
/* transmit 1 message */
TxMessage.StdId=0x00; // 标准标识符为0
TxMessage.ExtId=0x1234; // 设置扩展标示符(29位)
TxMessage.IDE=CAN_ID_EXT; // 使用扩展标识符
TxMessage.RTR=CAN_RTR_DATA; // 消息类型为数据帧,一帧8位
TxMessage.DLC=2; // 发送两帧信息
TxMessage.Data[0]=0xDE; // 第一帧信息
TxMessage.Data[1]=0xCA; // 第二帧信息
CAN_Transmit(CAN1, &TxMessage);
/* initialize the value that will be returned */
ret = 0xFF;
/* receive message with interrupt handling */
i=0;
while((ret == 0xFF) && (i < 0xFFF))
{
i++;
}
if (i == 0xFFF)
{
ret=0;
}
/* disable interrupt handling */
CAN_ITConfig(CAN1, CAN_IT_FMP0, DISABLE);
return (TestStatus)ret;
}
5、CAN的中断处理函数
检查是否接收到正确的消息。如果消息正确则设置标识符为1 否则设置为0
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
RxMessage.StdId=0x00;
RxMessage.ExtId=0x00;
RxMessage.IDE=0;
RxMessage.DLC=0;
RxMessage.FMI=0;
RxMessage.Data[0]=0x00;
RxMessage.Data[1]=0x00;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
if((RxMessage.ExtId==0x1234) && (RxMessage.IDE==CAN_ID_EXT)
&& (RxMessage.DLC==2) && ((RxMessage.Data[1]|RxMessage.Data[0]<<8)==0xDECA))
{
ret = 1;
}
else
{
ret = 0;
}
}
6、这个实验比zangchao的简单多了。只是完成了LoopBack,没有进行协议转换和双机通讯。还比较弱智的说
7、例行性的上图
CAN 回环数据串口监视

CAN LoopBack时的寄存器

查看系统寄存器的方法
今天参考野火程序,弄了下CAN。还不错 Loopback模式正常收发数据。
配置CAN为中断接收模式
参考了野火的程序实现。
这里基本就是我对野火程序的理解,和拷贝
1、设置NVIC 使能CAN中断接收
static void CAN_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable CAN1 RX0 interrupt IRQ channel */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 主优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
2、引脚GPIO设置
板子上的CAN引脚被从定义到了PB8和PB9.
需要使用AFIO的Renap功能
static void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
/* CAN1 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* Configure CAN pin: RX */ // PB8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure CAN pin: TX */ // PB9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
//将CAN1引脚重定义到PB8 PB9 使用引脚服用功能
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
}
3、将CAN配置为LoopBack模式
配置完成后发送一帧数据,并接收。以检查是否配置成功,此处的接收使用了查询方式
TestStatus CAN_Polling(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
CanRxMsg RxMessage;
uint32_t i = 0;
uint8_t TransmitMailbox = 0;
/* CAN register init */
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE; // 时间触发通信禁止
CAN_InitStructure.CAN_ABOM=DISABLE; // 离线退出是在中断置位清0后退出
CAN_InitStructure.CAN_AWUM=DISABLE; // 自动唤醒模式:清零sleep
CAN_InitStructure.CAN_NART=DISABLE; // 自动重新传送豹纹,知道发送成功
CAN_InitStructure.CAN_RFLM=DISABLE; // FIFO没有锁定,新报文覆盖旧报文
CAN_InitStructure.CAN_TXFP=DISABLE; // 发送报文优先级确定:标志符
CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; // 回环模式
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // 1tq、BS1、BS2的值跟波特率有关
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=5; // 分频系数为5
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
/* CAN 过滤器初始化 */
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //标识符过滤
//使用32位过滤器,接收报文标识符的每一位都必须跟过滤器标识符相同
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //设置标识符
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0; //接收FIFO
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能过滤器
CAN_FilterInit(&CAN_FilterInitStructure);
/* transmit */
TxMessage.StdId=0x11; // 设定标准标识符(11位,扩展的为29位)
TxMessage.RTR=CAN_RTR_DATA; // 传输消息的帧类型为数据帧(还有远程帧)
TxMessage.IDE=CAN_ID_STD; // 消息标志符实验标准标识符
TxMessage.DLC=2; // 发送两帧,一帧8位
TxMessage.Data[0]=0xCA; // 第一帧数据
TxMessage.Data[1]=0xFE; // 第二帧数据
TransmitMailbox=CAN_Transmit(CAN1, &TxMessage); //处理好数据后,将数据贞挂号等待发送。
i = 0;
// 用于检查消息传输是否正常
while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFF))
{
i++;
}
i = 0;
// 检查返回的挂号的信息数目
while((CAN_MessagePending(CAN1, CAN_FIFO0) < 1) && (i != 0xFF))
{
i++;
}
/* receive */
RxMessage.StdId=0x00;
RxMessage.IDE=CAN_ID_STD;
RxMessage.DLC=0;
RxMessage.Data[0]=0x00;
RxMessage.Data[1]=0x00;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
if (RxMessage.StdId!=0x11)
{
return FAILED;
}
if (RxMessage.IDE!=CAN_ID_STD)
{
return FAILED;
}
if (RxMessage.DLC!=2)
{
return FAILED;
}
/* 判断发送的信息和接收的信息是否相等 */
if ((RxMessage.Data[0]<<8|RxMessage.Data[1])!=0xCAFE)
{
return FAILED;
}
//printf("receive data:0X%X,0X%X",RxMessage.Data[0], RxMessage.Data[1]);
return PASSED; /* Test Passed */
}
4、配置CAN的中断接收
TestStatus CAN_Interrupt(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
uint32_t i = 0;
/* CAN register init */
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE; // 时间触发通信禁止
CAN_InitStructure.CAN_ABOM=DISABLE; // 离线退出是在中断置位清0后退出
CAN_InitStructure.CAN_AWUM=DISABLE; // 自动唤醒模式:清零sleep
CAN_InitStructure.CAN_NART=DISABLE; // 自动重新传送豹纹,知道发送成功
CAN_InitStructure.CAN_RFLM=DISABLE; // FIFO没有锁定,新报文覆盖旧报文
CAN_InitStructure.CAN_TXFP=DISABLE; // 发送报文优先级确定:标志符
CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; // 回环模式
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // 1tq、BS1、BS2的值跟波特率有关
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler=1; // 分频系数为1
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
/* CAN filter init */
CAN_FilterInitStructure.CAN_FilterNumber=1;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
/* CAN FIFO0 message pending interrupt enable */
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //中断使能
/* transmit 1 message */
TxMessage.StdId=0x00; // 标准标识符为0
TxMessage.ExtId=0x1234; // 设置扩展标示符(29位)
TxMessage.IDE=CAN_ID_EXT; // 使用扩展标识符
TxMessage.RTR=CAN_RTR_DATA; // 消息类型为数据帧,一帧8位
TxMessage.DLC=2; // 发送两帧信息
TxMessage.Data[0]=0xDE; // 第一帧信息
TxMessage.Data[1]=0xCA; // 第二帧信息
CAN_Transmit(CAN1, &TxMessage);
/* initialize the value that will be returned */
ret = 0xFF;
/* receive message with interrupt handling */
i=0;
while((ret == 0xFF) && (i < 0xFFF))
{
i++;
}
if (i == 0xFFF)
{
ret=0;
}
/* disable interrupt handling */
CAN_ITConfig(CAN1, CAN_IT_FMP0, DISABLE);
return (TestStatus)ret;
}
5、CAN的中断处理函数
检查是否接收到正确的消息。如果消息正确则设置标识符为1 否则设置为0
void USB_LP_CAN1_RX0_IRQHandler(void)
{
CanRxMsg RxMessage;
RxMessage.StdId=0x00;
RxMessage.ExtId=0x00;
RxMessage.IDE=0;
RxMessage.DLC=0;
RxMessage.FMI=0;
RxMessage.Data[0]=0x00;
RxMessage.Data[1]=0x00;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
if((RxMessage.ExtId==0x1234) && (RxMessage.IDE==CAN_ID_EXT)
&& (RxMessage.DLC==2) && ((RxMessage.Data[1]|RxMessage.Data[0]<<8)==0xDECA))
{
ret = 1;
}
else
{
ret = 0;
}
}
6、这个实验比zangchao的简单多了。只是完成了LoopBack,没有进行协议转换和双机通讯。还比较弱智的说
7、例行性的上图
CAN 回环数据串口监视

CAN LoopBack时的寄存器

查看系统寄存器的方法


105楼
体验硬件CRC
看看手册,STM32中有一个硬件CRC发生器。使用也比较简单:
1、开启CRC时钟
2、向CRC_DR寄存器中写入要计算的数据
3、从CRC_DR中读出数据
下边是代码:
1、初始化函数,开时钟
void CRC_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
}
2、计算数据块的CRC
CRCValue = CRC_CalcBlockCRC((uint32_t *)DataBuffer, BUFFER_SIZE); //计算一个数据块的CRC
按F12跟着进去,感觉这个CRC_CalcBlockCRC有问题。好像只返回了最后一个数据的CRC。并没有真正计算
查看手册才发现有这样的描述:每一次写入数据寄存器,其计算结果是前一次CRC计算结果和新计算结果的组合(对整个32位字进行CRC计算,而不是逐字节地计算)。
所以,计算结果就是这个样子的。
如果需要获得单独这组数据的计算结果,在计算之前应先使用CRC_ResetDR()复位CRC_DR寄存器。
3、计算单个数据的CRC
(1)寄存器方式
CRC->DR = DataBuffer[i]; //计算一个数据的CRC
CRCValue = CRC->DR;
(2)库函数方式
CRCValue = CRC_CalcCRC(DataBuffer[i]);
对比两种方式结果是一样的
注:根据前面的说明,要获得单个数据的CRC,在计算前也要复位CRC_DR寄存器。
4、获得CRC结果后,可以使用printf将结果打印到电脑查看:
printf("32-位数据 CRC 校验码为:0X%X\r\n", CRCValue);
4、要抓的图太多了。我想已经够明白了,不需要再贴图了
看看手册,STM32中有一个硬件CRC发生器。使用也比较简单:
1、开启CRC时钟
2、向CRC_DR寄存器中写入要计算的数据
3、从CRC_DR中读出数据
下边是代码:
1、初始化函数,开时钟
void CRC_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
}
2、计算数据块的CRC
CRCValue = CRC_CalcBlockCRC((uint32_t *)DataBuffer, BUFFER_SIZE); //计算一个数据块的CRC
按F12跟着进去,感觉这个CRC_CalcBlockCRC有问题。好像只返回了最后一个数据的CRC。并没有真正计算
查看手册才发现有这样的描述:每一次写入数据寄存器,其计算结果是前一次CRC计算结果和新计算结果的组合(对整个32位字进行CRC计算,而不是逐字节地计算)。
所以,计算结果就是这个样子的。
如果需要获得单独这组数据的计算结果,在计算之前应先使用CRC_ResetDR()复位CRC_DR寄存器。
3、计算单个数据的CRC
(1)寄存器方式
CRC->DR = DataBuffer[i]; //计算一个数据的CRC
CRCValue = CRC->DR;
(2)库函数方式
CRCValue = CRC_CalcCRC(DataBuffer[i]);
对比两种方式结果是一样的
注:根据前面的说明,要获得单个数据的CRC,在计算前也要复位CRC_DR寄存器。
4、获得CRC结果后,可以使用printf将结果打印到电脑查看:
printf("32-位数据 CRC 校验码为:0X%X\r\n", CRCValue);
4、要抓的图太多了。我想已经够明白了,不需要再贴图了

106楼
ENC-03MB模块(单轴陀螺仪)驱动成功
ENC-03MB是小日本产的单轴陀螺仪。有以下几个特点:
1、供电电压 2.7~5.25
2、参考电压 1.25~1.45 典型值为1.35V
3、比例系数 0.67mV/deg/s
4、静态输出 Vref+/-0.6
需要的Vref为1.35V 手上没有咋办?
站不是搞定了DAC吗?使用DAC输出1.35V参考电压供ENC模块使用
步骤如下:
1、使用前面做过的的DAC实验,输出1.35V电压
使用定时器触发:My_DAC2_Init();将DAC数据寄存器的值设置为0x69
输出后使用三用表测试下,输出1.34V多点
2、ADC初始化
前面也提到过,当时没有电压可测试,值测试了3.3V和0V的输出。
今天拿来实验。由于使用的是DMA方式,只需要读数据就OK了
3、将读出的数据进行简单的滤波串口打印
很简单的滤波,取100次采集到数据的平均值
卡尔曼滤波效果比较不错,可惜俺不会。
while(1)
{
//if(ADC_ConvertedValue>2000)
adctemp+= ADC_ConvertedValue;
i++;
//进行简单的滤波后输出
if(i == 100)
{
printf("%d\r\n",adctemp/100);
i = 0;
adctemp = 0;
}
}

摇晃陀螺仪时候的输出:
ENC-03MB是小日本产的单轴陀螺仪。有以下几个特点:
1、供电电压 2.7~5.25
2、参考电压 1.25~1.45 典型值为1.35V
3、比例系数 0.67mV/deg/s
4、静态输出 Vref+/-0.6
需要的Vref为1.35V 手上没有咋办?
站不是搞定了DAC吗?使用DAC输出1.35V参考电压供ENC模块使用
步骤如下:
1、使用前面做过的的DAC实验,输出1.35V电压
使用定时器触发:My_DAC2_Init();将DAC数据寄存器的值设置为0x69
输出后使用三用表测试下,输出1.34V多点
2、ADC初始化
前面也提到过,当时没有电压可测试,值测试了3.3V和0V的输出。
今天拿来实验。由于使用的是DMA方式,只需要读数据就OK了
3、将读出的数据进行简单的滤波串口打印
很简单的滤波,取100次采集到数据的平均值
卡尔曼滤波效果比较不错,可惜俺不会。
while(1)
{
//if(ADC_ConvertedValue>2000)
adctemp+= ADC_ConvertedValue;
i++;
//进行简单的滤波后输出
if(i == 100)
{
printf("%d\r\n",adctemp/100);
i = 0;
adctemp = 0;
}
}

摇晃陀螺仪时候的输出:




109楼
参考SPI1代码
但有个地方必须改好
初始化代码如下
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
SPI_I2S_DeInit(SPI2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
//SPI2挂在APB1上,别搞错了
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Configure SPI2 pins: SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //分别对应SPI2_CLK、SPI3_MISO、SPI4_MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//SPI_CPOL_High; //选择了串行时钟的稳态:时钟悬空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//SPI_CPHA_2Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
/* Enable SPI1 */
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}
但有个地方必须改好
初始化代码如下
void SPI2_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
SPI_I2S_DeInit(SPI2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
//SPI2挂在APB1上,别搞错了
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Configure SPI2 pins: SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //分别对应SPI2_CLK、SPI3_MISO、SPI4_MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//SPI_CPOL_High; //选择了串行时钟的稳态:时钟悬空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//SPI_CPHA_2Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
/* Enable SPI1 */
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}

110楼
收发数据代码基本相同
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
//while((SPI1->SR&1<<1)==0)//等待发送区空
/* Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;
/* Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //检查指定的SPI标志位设置与否:接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
//while((SPI1->SR&1<<1)==0)//等待发送区空
/* Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;
/* Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //检查指定的SPI标志位设置与否:接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
回复
有奖活动 | |
---|---|
发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
【EEPW在线】E起听工程师的声音! | |
“我踩过的那些坑”主题活动——第001期 | |
高校联络员开始招募啦!有惊喜!! | |
【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
送您一块开发板,2025年“我要开发板活动”又开始了! | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏10分 | |
【我踩过的那些坑】DRC使用位置错误导致的问题被打赏100分 | |
我踩过的那些坑之混合OTL功放与落地音箱被打赏50分 | |
汽车电子中巡航控制系统的使用被打赏10分 | |
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏100分 | |
分享汽车电子中巡航控制系统知识被打赏10分 | |
分享安全气囊系统的检修注意事项被打赏10分 | |
分享电子控制安全气囊计算机知识点被打赏10分 | |
【分享开发笔记,赚取电动螺丝刀】【OZONE】使用方法总结被打赏20分 | |
【分享开发笔记,赚取电动螺丝刀】【S32K314】芯片启动流程分析被打赏40分 |