DALI1.0学习——BIT解码

最近在学习DALI调光相关知识并下载了Microchip提供的基于ATMega88PA的软件工程及硬件设计参考方案。写这些文章的目的就是把自己对知识的理解作一些梳理。

芯片厂果然专业,考虑得相当周到,为了芯片销量连软件和硬件方案全都提供了。芯片厂关于DALI1.0实现的软硬件参考链接地址如下:Salesforceicon-default.png?t=N7T8https://microchip.my.salesforce.com/sfc/p/#o0000000KAkK/a/3l000001Iuci/0yucLkmht5A3PuLOo2MVtWQlQA1Ca1FgNK1KkCKafeg

Firmware部分是DALI1.0实现的源代码,包括底层驱动及上层应用,使用AVR系列专用开发IDE:Microchip Studio。

这一篇主要理解下如何解码主机发送来的BIT信号,重点是dali_bit.c文件,关于DALI主机发送数据的时序可以参考这篇博文:DALI通信及C语言实现 - 斑鸠,一生。 - 博客园 (cnblogs.com)

主机和从机通信使用半双工,波特率为1200,参考示例中从机使用GPIO的边沿跳变(上升沿和下降沿都触发)结合定时器来解码主机发送来的信号,具体配置如下:

1、GPIO为双边沿跳变中断,中断处理完成后定时器计数清零;

2、定时器溢出时间为32微秒。1200BIT/S的波特率传输一个BIT的时间约833微秒,半个BIT,也就是一个TE为416微秒,所以定时器约溢出13次左右,曼切斯特编码是在传输一半BIT时间的时候产生边沿跳变,传输1就是上升沿,0是下降沿;

定时器和GPIO配置完成后,就开始等待主机发送前向帧,从机解析数据的思路如下:

1、总线在没有数据发送时,从机的接收引脚(也就是双边沿跳变引脚)一直是高电平;

2、当主机发送起始号时,从机的接收引脚会检测到一个下降沿,当经过约半个BIT的时间后如果检测到一个上升沿,则证明是有效的起始信号,进入准备接收信号阶段;

3、以后每隔两个TE就读取一次实际传输的BIT,如图1所示,同时不停检测是否有连续4个TE,如果数据接收完成后出现4个连续TE,证明是接收到了停止位,本次数据接收成功,如果数据没有接收完成就出现4个TE说明传输出错;

图1:DALI时序

4、正确检测到停止位后,将接收到的地址和数据递交给上一层进行帧逻辑处理。

再来看源代码文件dali_bit.c,DALI从机的接收引脚边沿跳变中断处理程序dali_bit_pcint_interrupt函数如下:

/*** \brief External pin interrupt handler** This is the handler for external pin interrupt*/
void dali_bit_pcint_interrupt(void)
{static uint8_t bit_index;uint8_t bit_index_temp;uint8_t dali_bit_rx;bit_index_temp = bit_index;pin_level = DALI_INPORT & (1 << DALI_INPUT);if (status_receive == 0) {if (pin_level == LOW) {/* dali bus falling edge indicates start bit */bit_index_temp = 0;status_receive = BIT_START;dali_rec_addr = 0;dali_rec_data = 0;}} else if (status_receive == BIT_START) {/* dali pin must be high after the second INT0 edge */if ((level_time > MIN_TE_CNT) && (level_time < MAX_TE_CNT)) {			/* get the start bit and get ready for 16 bit data. */status_receive = BIT_0;bit_index_temp += 1;} else {/* Start bit error */status_receive = 0;}} else if (status_receive < BIT_STOP1) {if (level_time > MIN_2TE_CNT) {/* Long level (2xTe) is detected */bit_index_temp += 2;} else if ((level_time > MIN_TE_CNT) &&(level_time < MAX_TE_CNT)) {/* Short level (1xTe) is detected */bit_index_temp += 1;} else {status_receive = 0;}if (bit_index_temp >= 34) { /* If the last Te is low (dali bit 0), a rising edge is* detected before stop bit */			 status_receive = BIT_STOP1;}/* Decode dali bit at every second Te bit */if (bit_index_temp & 0x01) {/* shift out the lowest bit to get dali bit */			dali_bit_rx = bit_index_temp >> 1;if (dali_bit_rx <= BIT_7) { //the current bit number, maximum 8 for the address byte/* get the address byte */dali_rec_addr <<= 1;if (pin_level) {dali_rec_addr |= 0x01;}} else {/* get the data byte */dali_rec_data <<= 1;if (pin_level) {dali_rec_data |= 0x01;if (dali_bit_rx == BIT_15) { /* if the last Te is high (dali bit 1), a Te * high period is added before stop bit */						 status_receive = BIT_STOP2;}}}}} else {status_receive = 0;}dali_slave_set_addr_to_service(dali_rec_addr);dali_slave_set_data_to_service(dali_rec_data);bit_index = bit_index_temp;TCNT0 = 0;level_time = 0;
}

代码分析:

1、由于在接收主机发送的数据时会多次进入边沿跳变中断,必须使用静态变量bit_index并结合变量bit_index_temp保存当前已获取的BIT索引,确切的说应该是TE索引,pin_level用于获取从机输入引脚的电平状态,变量status_receive表示当前接收的是起始信号、数据还是停止位;

2、当主机发送起始信号时会触发第一个下降沿,第16行判断如果DALI输入引脚是低电平,则初始化一些变量,并将接收状态转为BIT_START,也就是起始信号;

3、起始信号下降沿触发后,第二次边沿跳变触发时必须是上升沿且触发时间必须是在一个TE周期内才被认为是正常的起始信号,如图2所示,Start部分先有一个下降沿然后一个上升沿才开始发送MSB。变量level_time会在定时器0的溢出中断处理程序中累加,溢出时间约为32微秒(8MHz频率不分频,最大计数256,溢出时间 = 256/8000000),约13个溢出周期后就是一个TE的时间:416微秒左右,当然这个时间不可能刚好,有正负5个溢出周期左右误差范围,所以第25行使用了if ((level_time > MIN_TE_CNT) && (level_time < MAX_TE_CNT))。此时变量bit_index_temp被设置为1,同时status_receive设置为准备接收第一个数据BIT,即BIT_0;

图2:起始信号,先一个下降沿然后一个上升沿

4、正确接收到起始信号后,准备接收地址和数据字节。代码第34行判断只要不是接收停止位就保存当前接收到的BIT。代码第35行到第41行判断:如果是经过两个TE时间才产生边沿跳变中断的话则将bit_index_temp加2,否则加1。当发送不同BIT值时就会出现两个TE后才会出现边沿跳变的情况,例如:前面的比特是0,后面接着是1就会出现连续两个TE的低电平然后产生上升沿跳变,如图3所示;

图3:BIT值改变时会有两个连续TE的高或低电平

5、代码第46行判断当bit_index_temp>=34时就将status_receive切换到接收停止位1,因为包括起始BIT、地址字节和数据字节共17个BIT,也就是34个TE,当接收到最后一个BIT并且是低电平,这里要注意:只有当最后一个BIT是低电平,bit_index_temp才会等于34,高电平应该是33。最后一个BIT是0且它后面出现上升沿则证明接收到的是停止位1

6、代码第53行到76行是解码接收到的BIT值并赋值给地址变量dali_rec_addr和数据变量dali_rec_data。首先第53行使用了if (bit_index_temp & 0x01),bit_index_temp必须为奇数且大于1时if条件才为真。那我们来看一下当接收地址和数据的BIT时,bit_index_temp是不是奇数并且对应的BIT是否正确,如图4所示,当起始位的上升沿产生后bit_index_temp被设置为1,然后从35行到41行根据边沿跳变触发时间将bit_index_temp加2或者加1,我们可以看到bit_index_temp确实是在每次为奇数时才读取接收到的BIT,为节省空间在图中我把bit_index_temp改为了bit_idx。

第1个红点位置:也就是有效起始信号上升沿中断时bit_idx = 1

第2个红点位置:由于经过两个TE才产生下降沿中断,bit_idx执行了加2,变成3,此时if (bit_index_temp & 0x01)条件为真,读取数据刚好是BIT值0,和曼切斯特编码含义一样

第3个红点位置:经过了两个TE产生了上升沿中断,bit_idx执行了加2,变成5,此时if (bit_index_temp & 0x01)条件为真,读取数据刚好是BIT值1,和曼切斯特编码含义一样

第4个红点位置:经过了1个TE产生了下降沿中断,bit_idx执行了加1,变成6,此时if (bit_index_temp & 0x01)条件为假,所以没有读取数据

第5个红点位置:经过了1个TE产生了上升沿中断,bit_idx执行了加1,变成7,此时if (bit_index_temp & 0x01)条件为真,读取数据刚好是BIT值1,和曼切斯特编码含义一样

第6个红点位置:经过了两个TE产生了下降沿中断,bit_idx执行了加2,变成9,此时if (bit_index_temp & 0x01)条件为真,读取数据刚好是BIT值0,和曼切斯特编码含义一样

后面的以此类推,可见确实是bit_index_temp变量为奇数且非起始位时才读取并保存BIT值。

图4:bit_index_temp为奇数时读取数据

7、dali_bit_rx用于判断当前接收到的是地址字节还是数据字节并计算出BIT号,BIT_0到BIT_15,对应值:1-16,小于等于BIT_7时是地址字节,否则就是数据字节。前面说过奇数位获取一次数据,每隔两个值计算一下当前的BIT序号,所以dali_bit_rx = bit_index_temp >> 1。代码第60行和第66行根据当前引脚的电平来保存数据,在第68行判断如果是最后一个数据BIT了,则设置接收状态为停止位2

8、最后几行代码主要将定时器0的计数值清零并且将定时器0溢出次数level_time清零。用局部静态变量保存当前的TE索引号,以便下次产生边沿跳变中断时赋值给bit_index_temp。

DALI1.0的比特解码部分就介绍到这里,后续继续整理其他内容,希望和大家一起学习交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/253399.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯day04——查询后矩阵的和

1.题目 给你一个整数 n 和一个下标从 0 开始的 二维数组 queries &#xff0c;其中 queries[i] [typei, indexi, vali] 。 一开始&#xff0c;给你一个下标从 0 开始的 n x n 矩阵&#xff0c;所有元素均为 0 。每一个查询&#xff0c;你需要执行以下操作之一&#xff1a; …

JavaSE基础50题:6. 求出0~999之间的所有“水仙花数”并输出

概念 “水仙花数”是指一个三位数&#xff0c;其各位数字的立方和确好等于该数本身。 如&#xff1a;153 135333,则153是一个“水仙花数”。 【方法】 如何获得每一位的数&#xff1a;如(153) 个位: 153 % 10 3 十位: 153 / 10 15 15 % 10 5 百位: 153 / 100 1 代码 pu…

书-用数组存储高于60低于70的人单独存起来

#include<stdio.h> # define N 10 //书-用数组存储高于60低于70的人单独存起来 int main(){float s[N]{68.2,62.3,63.4,34.5,45.6,56.7,67.8,78.9,89.0,100};int i;float diyu[100];int j0;for(i0;i<N;i){if(s[i]>60 && s[i]<70)diyu[j]s[i];//这里的范…

消息队列zookeeper集群+kafka

消息队列zookeeper集群kafka kafka 3.0之前依赖于zookpeeper zookeeper开源分布式架构&#xff0c;提供协调服务&#xff08;Apache项目&#xff09; 基于观察者模式设计的分布式服务管理架构 存储和管理数据。分布式节点的服务结束观察者的注册&#xff0c;一旦分布式节点…

docker搭建logstash和使用方法

配置logstash 查询下载镜像【固定和elasticsearch一样的版本】 [roothao ~]# docker search logstash NAME DESCRIPTION STARS OFFICIAL AUTOMATED logstash …

【数据分享】11个城市的出租车(网约车)数据(免费获取)

出租车&#xff08;网约车&#xff09;GPS数据是我们最常使用的交通大数据之一&#xff0c;但是出租车&#xff08;网约车&#xff09;GPS数据没有公开的获取渠道&#xff0c;有些学者可能能通过与相关机构合作拿到数据&#xff0c;但是对于绝大多数普通人是没有这个机会的&…

LeetCode Hot100 200.岛屿数量

题目&#xff1a; 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以…

2023年最详细介绍Linux 系统目录结构!你确定不来了解一下吗?

&#x1f4da;&#x1f4da; &#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; ​​​ &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有…

AWS CodeWhisperer:基于机器学习的代码建议工具

#AWS CodeWhisperer&#xff1a;基于机器学习的代码建议工具 AWS CodeWhisper概述 Amazon CodeWhisperer 是一种基于机器学习&#xff08;ML&#xff09;的服务&#xff0c;它可以根据Amazon CodeWhisperer 是一种基于机器学习&#xff08;ML&#xff09;的服务&#xff0c;它…

Java---接口讲解

文章目录 1. 接口概述2. 接口特点3. 接口成员特点4. 小案例应用5. 类和接口的关系6. 抽象类和接口区别 1. 接口概述 1. 接口是一种公共的规范标准&#xff0c;只要符合规范标准&#xff0c;大家都可以通用。Java中的接口更多的是体现在对行为的抽象。 2. 参考生活中的接口可以理…

玩弄GPTs:人人都会的Prompt模板

角色定义 分享一个自用的Prompt模板&#xff0c;只要学会了这个模板&#xff0c;当遇到新场景时&#xff0c;直接套用就行。 简单总结&#xff1a; 角色定义(Master)背景(Background)规则(rule)技能(skill)限制(constaints)工作流(workflow) 经过实际测试发现&#xff0c;这…

Gti GUI添加标签

通过Git Gui打开项目&#xff0c;通过菜单打开分支历史&#xff0c;我这里是名为"develop"的分支 选中需要打标签的commit&#xff0c;右键-Create tag即可 但貌似无法删除标签&#xff0c;只能通过git bash

IOday4作业

使用两个子进程完成两个文件的拷贝&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程用于回收两个子进程的资源 #include<myhead.h>int main(int argc, const char *argv[]) {int pid-1;int fd -1;int fa -1;int fb -1;//求出文…

Splashtop 荣获 SDC“年度安全供应商”奖

2023年12月5日 荷兰阿姆斯特丹 Splashtop 是随处办公环境改革的先驱&#xff0c;在伦敦举办的第14届 SDC 颁奖典礼上荣获“年度安全供应商”奖&#xff0c;我们对此感到十分自豪。荣获这一知名奖项凸显了 Splashtop 致力于通过企业级加密和基于权限的访问保护不同规模组织的决…

【精选】MyFileServer (超详细思路过程)

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

JVM 类加载机制(七)

1.加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化 ​ JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;下面我们就分别来看一下这五个过程。 1.1. 加载 ​ 加载是类加…

强化学习第1天:强化学习概述

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​​ 文章目录 介绍 强化学习要素 强化学习任务示例 环境搭建&#xff1a;gym 基本用法 环境信息查看 创建智能体 过程可视化 完整代码 结语…

代码随想录算法训练营第三十六天|01背包问题 二维 ,01背包问题 一维 ,416. 分割等和子集

背包理论基础 01 背包&#xff08;二维&#xff09; 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 背包最大重量为4。 物品为&#x…

Python小案例:while练习题

目录 while练习题&#xff1a;1、存款多少年能翻倍2.小球坠落长度计算3、猴子吃桃4、计算&#xff1a;1-23-4...99-100的和 while练习题&#xff1a; 1、存款多少年能翻倍 1万本金&#xff0c;年利息&#xff1a;0.0325&#xff0c;求连本带息多少年能翻倍 解析&#xff1a;…

Codeforces Round 913 (Div. 3) A~E(F,G更新中)

A.Rook&#xff08;循环&#xff09; 题意&#xff1a; 给出一个 8 8 8 \times 8 88的棋盘和一个棋子&#xff08;可以任选上下左右四方向移动任意步数&#xff09;&#xff0c;问一次移动可以到达哪些格子。 分析&#xff1a; 使用for循环对棋子所在的行列进行遍历并输出…