今天来聊一聊一个超级简单的电路。 相信很多小伙伴在设计的时候做按键检测的时候,都是一个按键对应一个GPIO口,除了矩阵按键外,独立按键大部分都是采用一对一的形式。 但是在一些场合,单片机的管脚有限的情况下(出于成本上考虑),并没有那么多的管脚去检测多个独立按键,那该怎么办? 采用ADC的方式,利用单片机内置的ADC来实现多个按键的检测,当然了,前提是单片机得内置ADC,实现原理图如下: R1为限流电阻,R2,R3,R4为不同阻值的电阻,当相对应的按键被按下时,R1就和R2,R3,R4中的其中一个组成电阻分压,从而使ADC输出不同的电压值,这时候程序里面就可以通过采集回来的电压去判断那个按键被按下了。
无锁栈(lock-free stack) 无锁数据结构意味着线程可以并发地访问数据结构而不出错。例如,一个无锁栈能同时允许一个线程压入数据,另一个线程弹出数据。不仅如此,当调度器中途挂起其中一个访问线程时,其他线程必须能够继续完成自己的工作,而无需等待挂起线程。 无锁栈一个很大的问题在于,如何在不加锁的前提下,正确地分配和释放节点的内存,同时不引起逻辑错误和程序崩溃。 一、使用智能指针std::shared_ptr实现 一个最朴素的想法是,使用智能指针管理节点。事实上,如果平台支持std::atomic_is_lock_free(&some_shared_ptr)实现返回true,那么所有内存回收问题就都迎刃而解了(我在X86和Arm平台测试,均返回false)。示例代码(文件命名为lock_free_stack.h)如下: #pragma once #include #include template <typename T>class LockFreeStack { public: LockFreeStack(): head_(nullptr) {} ~LockFreeStack() { while (Pop()) { // Do nothing and wait for all elements are poped. } } LockFreeStack(const LockFreeStack& other) = delete; LockFreeStack& operator=(const LockFreeStack& other) = delete; bool IsEmpty() const { return std::atomic_load(&head_) == nullptr; } void Push(const T& data) { const auto new_node = std::make_shared(data); new_node->next = std::atomic_load(&head_); // If new_node->next is the same as head_, update head_ to new_node and // return true. // If new_node->next and head_ are not equal, update new_node->next to head_ // and return false. while ( !std::atomic_compare_exchange_weak(&head_, &new_node->next, new_node)) { // Do nothing and wait for the head_ is updated to new_node. } } std::shared_ptrPop() { std::shared_ptrold_head = std::atomic_load(&head_); // If old_head is not a null pointer and it is the same as head_, update // head_ to old_head->next and return true. // If old_head is not a null pointer and it is not equal to head_, update // old_head to head_ and return false. while (old_head != nullptr && !std::atomic_compare_exchange_weak( &head_, &old_head, std::atomic_load(&old_head->next))) { // Do nothing and wait for the head_ is updated to old_head->next. } if (old_head != nullptr) { std::atomic_store(&old_head->next, std::shared_ptr()); return old_head->data; } return std::shared_ptr(); } private: struct Node { // std::make_shared does not throw an exception. Node(const T& input_data) : data(std::make_shared(input_data)), next(nullptr) {} std::shared_ptrdata; std::shared_ptrnext; }; std::shared_ptrhead_;}; 上述代码中,希望借助std::shared_ptr<>来完成节点内存的动态分配和回收,因为其有内置的引用计数机制。不幸地是,虽然std::shared_ptr<>虽然可以用于原子操作,但在大多数平台上不是无锁的,需要通过C++标准库添加内部锁来实现原子操作,这样会带来极大的性能开销,无法满足高并发访问的需求。 如果编译器支持C++20标准,std::atomic允许用户原子地操纵std::shared_ptr,即在确保原子操作的同时,还能正确地处理引用计数。与其他原子类型一样,其实现也不确定是否无锁。使用std::atomic实现无锁栈(表面上看肯定无锁,实际上是否无锁取决于std::atomic的is_lock_free函数返回值是否为true)的示例代码(文件命名为 lock_free_stack.h)如下: #pragma once #include #include template <typename T>class LockFreeStack { public: LockFreeStack() : head_(nullptr) {} ~LockFreeStack() { while (Pop()) { // Do nothing and wait for all elements are poped. } } LockFreeStack(const LockFreeStack& other) = delete; LockFreeStack& operator=(const LockFreeStack& other) = delete; bool IsEmpty() const { return std::atomic_load(&head_) == nullptr; } void Push(const T& data) { const auto new_node = std::make_shared(data); std::shared_ptrold_head = head_.load(); new_node->next = old_head; // If old_head is the same as head_, update head_ to new_node and return // true. If old_head and head_ are not equal, update old_head to head_ and // return false. while (!head_.compare_exchange_weak(old_head, new_node)) { new_node->next = old_head; } } std::shared_ptrPop() { std::shared_ptrold_head = head_.load(); // If old_head is not a null pointer and it is the same as head_, update // head_ to old_head->next and return true. // If old_head is not a null pointer and it is not equal to head_, update // old_head to head_ and return false. while (old_head != nullptr && !head_.compare_exchange_weak(old_head, old_head->next.load())) { // Do nothing and wait for the head_ is updated to old_head->next. } if (old_head != nullptr) { old_head->next = std::shared_ptr(); return old_head->data; } return std::shared_ptr(); } private: struct Node { // std::make_shared does not throw an exception. Node(const T& input_data) : data(std::make_shared(input_data)), next(nullptr) {} std::shared_ptrdata; std::atomic<std::shared_ptr> next; }; // Compilation error: /usr/include/c++/9/atomic:191:21: error: static // assertion failed: std::atomic requires a trivially copyable type // static_assert(__is_trivially_copyable(_Tp), std::atomic<std::shared_ptr> head_;}; 我的编译器目前只支持C++17标准,上述代码会出现如下编译错误: In file included from /home/zhiguohe/code/excercise/lock_freee/lock_free_stack_with_shared_ptr_cpp/lock_free_stack_with_shared_ptr.h:3, from /home/zhiguohe/code/excercise/lock_freee/lock_free_stack_with_shared_ptr_cpp/lock_free_stack_with_shared_ptr.cpp:1:/usr/include/c++/9/atomic: In instantiation of ‘struct std::atomic
网上购买了一个8通道的RTD采集模块,原价要220元,参数如下:\x0d\x0a\x0d\x0a应用领域:\x0d\x0a\x0d\x0a1:各种工业现场。 \x0d\x0a\x0d\x0a2:超低温或高温应用等。
近日,一位电友遇到了棘手问题:客户家中的零线频繁烧毁,即便更换为25平方毫米的粗线,问题依旧在短短数日内重现。面对这一困境,他感到束手无策,于是向广大电友求助,希望能找到问题的根源及解决方案。 电友A的见解: 电友A分析,问题可能源于三相不平衡,而这种不平衡很可能是由谐波干扰引起的。他推测,谐波的产生可能与家中大量使用的LED灯及其镇流器有关。这些设备可能导致高压限流,进而产生谐波。他建议,如果家中220V转12V的电源转换器较多,可以尝试安装奇次谐波抑制器来解决问题。 电友B的解读: 电友B则认为,问题根源在于负荷中存在产生3次谐波的设备。3次谐波会改变三相电的夹角,导致零线电流增大,极端情况下,零线电流甚至可能达到相线电流的3倍。 电友C的实战经验: 电友C结合个人经验指出,零线烧毁主要有两个原因:一是虚接,二是三相严重不平衡。他同样提到,LED灯的驱动器容易产生大量谐波,这是零线电流过大的主要原因。虽然理论上可以使用谐波消除器来减少谐波,降低零线电流,但他个人并未尝试过这种方法。他分享了自己的解决方案:增加主零线。他原本的主零线是70平方毫米,后来增加了一根120平方毫米的零线,与原来的70平方毫米零线并行工作,从而解决了零线发烫的问题。 零线烧毁的原因可能涉及多个方面,以下是一些主要原因及解释: 零线接头问题: 零线的接头如果没有接好,可能会因为接触不良而产生火花,长时间下来会导致零线烧焦。 接头处如果处理不合格,如螺丝未锁紧导致虚接,也可能引发零线烧毁。 零线规格不当: 如果零线太细,而所承载的负荷过大,会导致零线超负荷运行,进而烧焦。 在一些情况下,所选择的零线比火线细,致使零线载流能力不足,也可能引发过热烧毁。 三相负载不平衡: 三相负载不平衡是导致零线电流过大的主要原因之一。当三相负载不平衡时,零线会储存电流,容易引发烧毁现象。 三次谐波的产生也可能加剧三相负载不平衡,使得零线电流进一步增大,甚至超过火线电流。 变压器或线路问题: 变压器内引出的线如果出现断路问题,也可能导致零线烧焦。 三相四线制的熔丝如果熔断,或者配电变压器的零线接线柱与导线连接接触不良,也可能引发零线断路或烧毁。 其他外部因素: 外部因素如大风刮断零线、车辆碰撞电杆或拉线等,也可能导致零线断路或烧毁。 非线性负载(如LED灯驱动器)产生的谐波电流,也可能使零线过热并烧毁。 针对零线烧毁的问题,可以采取以下措施进行预防和解决: 确保零线接头连接牢固,避免接触不良和虚接现象。 根据负荷情况选择合适的零线规格,避免超负荷运行。 尽量保持三相负载平衡,减少谐波电流的产生。 定期检查和维护变压器及线路,确保线路连接良好、无断路问题。 对于易受外部因素影响的零线,应加强防护措施,如增加防风、防撞设施等。 综上所述,零线频繁烧毁的问题可能涉及三相不平衡、谐波干扰等多个方面。针对这一问题,可以尝试安装谐波抑制器、优化负荷分布、增加主零线等方法进行解决。但具体方案还需根据实际情况进行选择和调整。希望这些建议能为遇到类似问题的电友提供有益的参考。
首先是供电部分,采用5V的LDO对输入电压进行降压(我没查到具体型号,用了78L05代替)输入部分有一个SOD4007的肖特基二极管作为防反接,这个还是蛮重要的(防呆),对于输出后的D2瞬态抑制二极管,
恒电流二极管的LED驱动电路设计介绍了。该方案在设计上简化了设计复杂度,成本大大低于采用开关电源的设计方案,同时其功率因数可以达到75%以上。