搜索
bottom↓
回复: 11

STM32F1 MDK 4.72 遇到了怪問題 求救

[复制链接]

出0入0汤圆

发表于 2019-3-29 14:45:10 | 显示全部楼层 |阅读模式

小弟再使用stm32F1 時,遇到了一個蠻怪的問題   想跟版上大神們求救                                
                                                                                                
1. 我宣告了這樣的變數                                                                          
                                                                                                
//==========================                                                                     
struct out00_bit_def{                                                                           
    u8  bit0               :1; // y00                                                            
    u8  bit1               :1; // y01                                                            
    u8  bit2               :1; // y02                                                            
    u8  bit3               :1; // y03                                                            
    u8  bit4               :1; // y04                                                            
    u8  bit5               :1; // y05                                                            
    u8  bit6               :1; // y06                                                            
    u8  bit7               :1; // y07                                                            
    }                                                                                            
                                                                                                
union{                                                                                          
    struct out00_bit_def bit;                                                                    
    u8  byte;                                                                                    
    }out00;                                                                                      
//==========================                                                                     
                                                                                                
2. 我在主程式中會使用下面的敘述,去改變 bit2 或 bit3 的狀態                                       
    out00.bit.bit2 = 1;                                                                          
    out00.bit.bit2 = 0;                                                                          
    out00.bit.bit3 = 1;                                                                          
    out00.bit.bit3 = 0;                                                                          
                                                                                                
3. 我在 timer中斷副程式中會使用下面的敘述,去改變 bit6 或 bit7 的狀態                             
    out00.bit.bit6 = 1;                                                                          
    out00.bit.bit6 = 0;                                                                          
    out00.bit.bit7 = 1;                                                                          
    out00.bit.bit7 = 0;                                                                          
                                                                                                
4. 很怪的問題是,當我程式RUN起來後,偶發性的會發生                                                
   中斷副程式有執行過改變 bit6 或 bit7 的狀態,但Memory中的bit卻沒有改變                     
   只有在timer中斷中執行改變的那些bit會出現異常
                                                  
   發生異常的情況像是中斷時執行out00.bit.bit6 = 1; 但執行後bit6沒有為1                           
                         或是中斷時執行 out00.bit.bit6 = 0; 但執行後bit6沒有為0                           

   主程式中所執行的bit狀態完全不會有異常                                                         
                                                                                                
5. 我猜測有可能是當主程式執行到類似 out00.bit.bit6 = 1; 這行程式時恰巧發生中斷,                  
   當主程式執行到 out00.bit.bit6 = 1; 時,雖然只是一行 C語法程式,但實際 CPU執行的行為依序是      
   a) 將記憶體中的 out00.byte 載入到 cpu的暫存器                                                
   b) 將這個 CPU暫存器的值 OR 0x40                                                               
   c) 將暫存器的值回寫到記憶體中 out00.byte                                                      
                                                                                                
   假設主程式執行到上面 a)動作之後,發生 timer中斷,timer中斷副程式中執行了 out00.bit.bit6 = 1;   
   然後結束中斷後回到主程式繼續從上面的 b)動作往下執行                                          
   因為這樣而發生了 timer中斷副程式中所作的動作無效(bit的狀態沒有被改變),                        
   事實上是timer中斷副程式的動作有執行 bit6狀態的改變了,只是回到主程式後又被覆蓋回先前的資料     
                                                                                                
6. 我為了要確認上面假設是對的,我宣告了另一個物件                                                
                                                                                                
   union{                                                                                       
       struct out00_bit_def bit;                                                                 
       u8  byte;                                                                                 
       }out01;                                                                                   
                                                                                                
   然後我在主程式中使用下面這樣的敘述去修改 bit2 或是 bit3的狀態                                 
    out01.bit.bit2 = 1;                                                                          
    out01.bit.bit2 = 0;                                                                          
    out01.bit.bit3 = 1;                                                                          
    out01.bit.bit3 = 0;                                                                          
                                                                                                
   也就是說,主程式中只能改變 out01.byte裡面的值 , timer中斷副程式中只能改變 out00.byte裡面的值   
   最終要拿出來使用的時候使用以下敘述                                                            
                                                                                                
   a = out00.byte | out01.byte;                                                                  
                                                                                                
   所得到的值就能夠正常,完全不會有"變更bit的狀態被 Lost"的事情發生                              
                                                                                                
   因為上面的測試,所以我猜測是因為主程式運行中,遇到timer中段所導致的問題
   
  A. 我在其他的單片機上從沒發生過這樣的問題
  B. 雖然目前用上面方法可以暫時規避問題,但如果我在主程式跟中斷成是中要操作相同的一個bit 還是會面臨同樣的問題

想問問板上各位大神們  有沒有遇過這樣的問題   何解?

                                                               

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2019-3-29 17:22:34 | 显示全部楼层
加个volatile试试看?

出870入263汤圆

发表于 2019-3-29 18:13:07 | 显示全部楼层
1,要把变量定义为volatile;
2,这种定义位操作实际上都是对同一个u8变量进行“读-改-写”操作,所以在中断和主循环中要保证互斥访问(最简单的互斥是“关中断-改变量-开中断”);

出0入0汤圆

发表于 2019-3-29 18:34:07 来自手机 | 显示全部楼层
都32bit的F1了,就不要用一个bit了……  咱不差那点空间。

出0入0汤圆

发表于 2019-3-29 19:06:40 | 显示全部楼层
楼主改变思路不要用位域
用arm提供的bit-band
专门映射了一块区域,把bit映射到word,单周期的

出0入0汤圆

发表于 2019-3-31 00:04:02 | 显示全部楼层
强制类型转换就能把位和字节转换了吧

出0入0汤圆

 楼主| 发表于 2019-3-31 18:42:30 | 显示全部楼层

我試過宣告成

union{                                                                                          
    struct out00_bit_def bit;                                                                    
    u8  byte;                                                                                    
    }volatile out00;      

問題還是會發生

出0入0汤圆

发表于 2019-4-1 18:47:24 | 显示全部楼层
原因是这种bit field的东西, 实际上还是用bit操作完成的,比如位与,位或。这样实际上大致会有3步。 1.把内存变量读入寄存器。2. 对寄存器位操作。3.把寄存器的数值保存到内存变量。这其中任何一步都可能被中断打断。 比如程序完成了第2步。被中断打断,中断改写了其中几位。然后程序恢复执行,继续执行第3布。中断改写的内容就丢失了。这种情况,用volatile是没有用处的。所以,要么你在写之前关闭中断,要么不要和中断同样写一个变量。你完全可以拆分成两个变量,一个程序写中断读,一个中断写程序读,这样只要加volatile标识就可以解决问题。

出0入0汤圆

发表于 2019-4-1 18:52:00 来自手机 | 显示全部楼层
很明显是读改写的问题。

出0入0汤圆

发表于 2019-4-1 18:55:44 来自手机 | 显示全部楼层
主程序,读了变量,改了变量,然后被中断,中断改了其他位,返回后主程序继续写,把中断的操作覆盖掉了。

出0入0汤圆

发表于 2019-4-2 10:40:11 | 显示全部楼层
一行C程序 会 对应多行的汇编

出0入0汤圆

发表于 2019-4-2 11:12:25 | 显示全部楼层
#pragma pack(1)//先测试下对齐方式
struct out00_bit_def{                                                                           
    u8  bit0               :1; // y00                                                            
    u8  bit1               :1; // y01                                                            
    u8  bit2               :1; // y02                                                            
    u8  bit3               :1; // y03                                                            
    u8  bit4               :1; // y04                                                            
    u8  bit5               :1; // y05                                                            
    u8  bit6               :1; // y06                                                            
    u8  bit7               :1; // y07                                                            
    }                                                                                            
                                                                                                
union{                                                                                          
    struct out00_bit_def bit;                                                                    
    u8  byte;                                                                                    
    }out00;     
#pragma pack()
外面加个这个你试下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 17:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表